fix(settings): correct heading order in account management sidebar

Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
pull/61505/head
Peter Ringelmann 2 months ago
parent 6cb5115eb3
commit b91fe68b6d
  1. 57
      apps/settings/src/components/AppNavigationGroupList.spec.ts
  2. 58
      apps/settings/src/components/AppNavigationGroupList.vue

@ -0,0 +1,57 @@
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { mount } from '@vue/test-utils'
import { ref } from 'vue'
import { describe, expect, it, vi } from 'vitest'
import NcAppNavigationCaption from '@nextcloud/vue/components/NcAppNavigationCaption'
// The component builds a real Vuex store via useStore(); mock it so this stays
// a focused component test that controls its own data.
vi.mock('../store/index.js', () => ({
useStore: () => ({
getters: {
getServerData: { isAdmin: false, isDelegatedAdmin: false },
getSortedGroups: [],
getSubAdminGroups: [],
getSearchQuery: '',
},
commit: vi.fn(),
dispatch: vi.fn(),
}),
}))
vi.mock('vue-router/composables', async (importActual) => ({
...(await importActual<object>()),
useRoute: () => ({ params: {} }),
useRouter: () => ({ push: vi.fn() }),
}))
vi.mock('../service/groups.ts', () => ({
searchGroups: () => Promise.resolve([]),
}))
vi.mock('@vueuse/core', async (importActual) => ({
...(await importActual<object>()),
useElementVisibility: () => ref(false),
}))
import AppNavigationGroupList from './AppNavigationGroupList.vue'
describe('AppNavigationGroupList', () => {
it('does not expose the group list as a heading (BITV 9.1.3.1a)', () => {
const wrapper = mount(AppNavigationGroupList)
// The sidebar group list is navigation, not document structure. It must
// not emit a heading, which would sit before the page <h1> in the DOM
// and produce an out-of-order outline (h2 before h1).
const caption = wrapper.findComponent(NcAppNavigationCaption)
expect(caption.exists()).toBe(true)
expect(caption.find('h1,h2,h3,h4,h5,h6').exists()).toBe(false)
// The "Groups" label is still rendered, just not as a heading.
expect(caption.text()).toContain('Groups')
})
})

@ -5,36 +5,6 @@
<template>
<Fragment>
<NcAppNavigationCaption
:name="t('settings', 'Groups')"
:disabled="loadingAddGroup"
:aria-label="loadingAddGroup ? t('settings', 'Creating group…') : t('settings', 'Create group')"
force-menu
is-heading
:open.sync="isAddGroupOpen">
<template v-if="isAdminOrDelegatedAdmin" #actionsTriggerIcon>
<NcLoadingIcon v-if="loadingAddGroup" />
<NcIconSvgWrapper v-else :path="mdiPlus" />
</template>
<template v-if="isAdminOrDelegatedAdmin" #actions>
<NcActionText>
<template #icon>
<NcIconSvgWrapper :path="mdiAccountGroupOutline" />
</template>
{{ t('settings', 'Create group') }}
</NcActionText>
<NcActionInput
v-model="newGroupName"
:label="t('settings', 'Group name')"
data-cy-users-settings-new-group-name
:label-outside="false"
:disabled="loadingAddGroup"
:error="hasAddGroupError"
:helper-text="hasAddGroupError ? t('settings', 'Please enter a valid group name') : ''"
@submit="createGroup" />
</template>
</NcAppNavigationCaption>
<p id="group-list-desc" class="hidden-visually">
{{ t('settings', 'List of groups. This list is not fully populated for performance reasons. The groups will be loaded as you navigate or search through the list.') }}
</p>
@ -42,6 +12,34 @@
class="account-management__group-list"
aria-describedby="group-list-desc"
data-cy-users-settings-navigation-groups="custom">
<NcAppNavigationCaption
:name="t('settings', 'Groups')"
:disabled="loadingAddGroup"
:aria-label="loadingAddGroup ? t('settings', 'Creating group…') : t('settings', 'Create group')"
force-menu
:open.sync="isAddGroupOpen">
<template v-if="isAdminOrDelegatedAdmin" #actionsTriggerIcon>
<NcLoadingIcon v-if="loadingAddGroup" />
<NcIconSvgWrapper v-else :path="mdiPlus" />
</template>
<template v-if="isAdminOrDelegatedAdmin" #actions>
<NcActionText>
<template #icon>
<NcIconSvgWrapper :path="mdiAccountGroupOutline" />
</template>
{{ t('settings', 'Create group') }}
</NcActionText>
<NcActionInput
v-model="newGroupName"
:label="t('settings', 'Group name')"
data-cy-users-settings-new-group-name
:label-outside="false"
:disabled="loadingAddGroup"
:error="hasAddGroupError"
:helper-text="hasAddGroupError ? t('settings', 'Please enter a valid group name') : ''"
@submit="createGroup" />
</template>
</NcAppNavigationCaption>
<GroupListItem
v-for="group in filteredGroups"
:id="group.id"

Loading…
Cancel
Save