From 6859203cebe3b6a31d23d55a3555bf36d6c73242 Mon Sep 17 00:00:00 2001 From: Derick Montague Date: Sat, 4 Apr 2020 14:02:34 -0500 Subject: Resolve header and nav accessibility violations - Add aria-label to nav sections in app-header and app-nav to meet accessibility guidelines. When application has multiple nav elements an aria-label is required to help screen readers identify the elements - Remove b-nav child of b-nav-bar in app-header to fix invalid markup generated by Bootstrap-vue components. Components were not used as expected by the component library - Replace b-nav-item with HTML
  • elements using nav-item css classes in order to use button elements. Bootstrap-vue generates elements which is not the semantic HTML element to use for items that are not links to other sections of the application. - Removed aria-expanded and nav-open class from nav-trigger button - Update appHeader unit test Used a TDD approach to write all tests to fail and then updated the methods and actions to make the tests suceed. Each test resulting in a dispatched action should be called once only and with the expected action. Signed-off-by: Derick Montague Change-Id: I18af3727708526f814b7ceb77a0c28fda9f3d9bd --- tests/unit/AppHeader.spec.js | 84 +++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 37 deletions(-) (limited to 'tests/unit/AppHeader.spec.js') diff --git a/tests/unit/AppHeader.spec.js b/tests/unit/AppHeader.spec.js index 6dea960b..52e45437 100644 --- a/tests/unit/AppHeader.spec.js +++ b/tests/unit/AppHeader.spec.js @@ -1,62 +1,72 @@ -import { mount } from '@vue/test-utils'; +import { shallowMount, createLocalVue, createWrapper } from '@vue/test-utils'; import Vue from 'vue'; +import Vuex from 'vuex'; import AppHeader from '@/components/AppHeader'; -import $store from '@/store'; -import { BootstrapVue } from 'bootstrap-vue'; + +// Silencing warnings about undefined Bootsrap-vue components +Vue.config.silent = true; +const localVue = createLocalVue(); +localVue.use(Vuex); describe('AppHeader.vue', () => { - let wrapper; - let spy; - Vue.use(BootstrapVue); + const actions = { + 'global/getHostStatus': sinon.spy(), + 'eventLog/getEventLogData': sinon.spy() + }; - wrapper = mount(AppHeader, { + const store = new Vuex.Store({ actions }); + const wrapper = shallowMount(AppHeader, { + store, + localVue, mocks: { - $t: key => key, - $store + $t: key => key } }); + // Reset spy for each test. Otherwise mutiple actions + // are dispatched in each test beforeEach(() => { - spy = sinon.spy($store.dispatch); + store.dispatch = sinon.spy(); }); - describe('Component exists', () => { - it('should check if AppHeader exists', async () => { - expect(wrapper.exists()); + describe('UI', () => { + it('should check if AppHeader exists', () => { + expect(wrapper.exists()).to.be.true; }); - }); - describe('AppHeader methods', () => { - it('should call getHostInfo and dispatch global/getHostStatus', async () => { - wrapper.vm.getHostInfo(); - spy('global/getHostStatus'); - expect(spy).to.have.been.calledWith('global/getHostStatus'); + it('should check if the skip navigation link exists', () => { + expect(wrapper.get('.link-skip-nav').exists()).to.be.true; }); - it('should call getEvents and dispatch eventLog/getEventLogData', async () => { - wrapper.vm.getEvents(); - spy('eventLog/getEventLogData'); - expect(spy).to.have.been.calledWith('eventLog/getEventLogData'); + it('refresh button click should emit refresh event', async () => { + wrapper.get('#app-header-refresh').trigger('click'); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted().refresh).to.exist; }); - it('should call refresh and emit refresh', async () => { - spy = sinon.spy(wrapper.vm.$emit); - wrapper.vm.refresh(); - spy('refresh'); - expect(spy).to.have.been.calledWith('refresh'); + it('nav-trigger button click should emit toggle:navigation event', async () => { + const rootWrapper = createWrapper(wrapper.vm.$root); + wrapper.get('#app-header-trigger').trigger('click'); + await wrapper.vm.$nextTick(); + expect(rootWrapper.emitted()['toggle:navigation']).to.exist; }); - it('should call logout and dispatch authentication/logout', async () => { - wrapper.vm.logout(); - spy('authentication/logout'); - expect(spy).to.have.been.calledWith('authentication/logout'); + it('logout button should dispatch authentication/logout', async () => { + wrapper.get('#app-header-logout').trigger('click'); + await wrapper.vm.$nextTick(); + expect(store.dispatch).calledWith('authentication/logout'); }); + }); - it('should call toggleNavigation and dispatch toggle:navigation', async () => { - spy = sinon.spy(wrapper.vm.$root.$emit); - wrapper.vm.toggleNavigation(); - spy('toggle:navigation'); - expect(spy).to.have.been.calledWith('toggle:navigation'); + describe('Methods', () => { + it('getHostInfo should dispatch global/getHostStatus', () => { + wrapper.vm.getHostInfo(); + expect(store.dispatch).calledWith('global/getHostStatus'); + }); + + it('getEvents should dispatch eventLog/getEventLogData', () => { + wrapper.vm.getEvents(); + expect(store.dispatch).calledWith('eventLog/getEventLogData'); }); }); }); -- cgit v1.2.3