Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion playwright/e2e/a11y-question-inputs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { test as formTest } from '../support/fixtures/form.ts'
import { test as appNavigationTest } from '../support/fixtures/navigation.ts'
import { test as randomUserTest } from '../support/fixtures/random-user.ts'
import { test as topBarTest } from '../support/fixtures/topBar.ts'
import { QuestionType } from '../support/sections/QuestionType.ts'
import { GridSubtype, QuestionType } from '../support/sections/QuestionType.ts'
import { FormsView } from '../support/sections/TopBarSection.ts'

const test = mergeTests(randomUserTest, appNavigationTest, formTest, topBarTest)
Expand All @@ -32,6 +32,9 @@ test.describe('Accessibility: aria attributes on question inputs', () => {
const questions = await form.getQuestions()
await questions[0].fillTitle('My question')
await questions[0].fillDescription('Some context')
await expect(questions[0].descriptionInput).toHaveAccessibleName(
'Description of question number 1',
)

await topBar.toggleView(FormsView.View)

Expand Down Expand Up @@ -148,6 +151,9 @@ test.describe('Accessibility: aria attributes on question inputs', () => {
page.getByRole('heading', { name: 'My dropdown question' }),
).toHaveId('q1_title')
await expect(page.locator('#q1_desc')).toContainText('Choose an option')
await expect(question.getByRole('combobox')).toHaveAccessibleName(
'My dropdown question',
)
})

test('Date question with description has aria-labelledby and aria-describedby', async ({
Expand Down Expand Up @@ -176,6 +182,9 @@ test.describe('Accessibility: aria attributes on question inputs', () => {
page.getByRole('heading', { name: 'My date question' }),
).toHaveId('q1_title')
await expect(page.locator('#q1_desc')).toContainText('Pick a date')
await expect(question.getByRole('textbox')).toHaveAccessibleName(
'My date question',
)
})

test('Linear scale question with description has aria-labelledby and aria-describedby', async ({
Expand All @@ -191,6 +200,18 @@ test.describe('Accessibility: aria attributes on question inputs', () => {
const questions = await form.getQuestions()
await questions[0].fillTitle('Rate your experience')
await questions[0].fillDescription('From 1 to 5')
await expect(
questions[0].section.getByRole('textbox', {
name: 'Label for lowest value',
exact: true,
}),
).toBeVisible()
await expect(
questions[0].section.getByRole('textbox', {
name: 'Label for highest value',
exact: true,
}),
).toBeVisible()

await topBar.toggleView(FormsView.View)

Expand Down Expand Up @@ -261,4 +282,27 @@ test.describe('Accessibility: aria attributes on question inputs', () => {
).toHaveId('q1_title')
await expect(page.locator('#q1_desc')).toContainText('Pick a color')
})

test('Grid cells are named by row and column', async ({
appNavigation,
form,
topBar,
page,
}) => {
await appNavigation.clickNewForm()
await form.fillTitle('Test form')

await form.addQuestion(QuestionType.Grid, GridSubtype.RadioButtons)
const questions = await form.getQuestions()
await questions[0].fillTitle('Satisfaction')
await questions[0].addColumn('Good')
await questions[0].addRow('Service')

await topBar.toggleView(FormsView.View)

const question = page.getByRole('listitem', { name: /Question number 1/ })
await expect(
question.getByRole('radio', { name: 'Service, Good' }),
).toBeAttached()
})
})
1 change: 1 addition & 0 deletions playwright/support/sections/FormSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class FormSection {
})
this.descriptionField = this.mainContent.getByRole('textbox', {
name: 'Description',
exact: true,
})
}

Expand Down
1 change: 1 addition & 0 deletions src/FormsSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
multiple
:options="availableGroups"
:placeholder="t('forms', 'Select groups')"
:aria-label-combobox="t('forms', 'Select groups')"
class="forms-settings__creation__multiselect"
label="displayName"
@update:modelValue="onCreationAllowedGroupsChange" />
Expand Down
1 change: 0 additions & 1 deletion src/components/OptionInputDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
<NcTextArea
v-model="enteredOptions"
:label="t('forms', 'Add multiple options (one per line)')"
:placeholder="t('forms', 'Add multiple options (one per line)')"
resize="vertical"
rows="10" />
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/components/Questions/Question.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@
ref="descriptionField"
dir="auto"
:value="description"
:aria-label="
t('forms', 'Description of question number {index}', {
index,
})
"
:placeholder="
t(
'forms',
Expand Down
1 change: 1 addition & 0 deletions src/components/Questions/QuestionDate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
:disabled="!readOnly"
:format="stringify"
:placeholder="datetimePickerPlaceholder"
:aria-label="text"
:showSecond="false"
:type="dateTimePickerType"
:disabledDate="disabledDates"
Expand Down
2 changes: 1 addition & 1 deletion src/components/Questions/QuestionDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
:options="choices"
:searchable="false"
label="text"
:aria-label-combobox="selectOptionPlaceholder"
:aria-label-combobox="text"
:aria-errormessage="hasError ? errorId : undefined"
:aria-invalid="hasError ? 'true' : undefined"
@invalid.prevent="validate"
Expand Down
2 changes: 2 additions & 0 deletions src/components/Questions/QuestionFile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
type="multiselect"
:modelValue="maxFileSizeUnit"
:options="availableUnits"
:aria-label-combobox="t('forms', 'File size unit')"
required
:clearable="false"
:searchable="false"
Expand Down Expand Up @@ -68,6 +69,7 @@
<NcActionInput
key="allowed-file-extensions-multiselect"
:label="t('forms', 'Custom file extensions')"
:aria-label-combobox="t('forms', 'Custom file extensions')"
type="multiselect"
multiple
taggable
Expand Down
4 changes: 4 additions & 0 deletions src/components/Questions/QuestionGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
:modelValue="values[row.id]"
:value="column.id.toString()"
:name="`${row.id}-answer`"
:aria-label="`${row.text}, ${column.text}`"
type="radio"
@update:modelValue="
onChangeCheckboxRadio(row.id, $event)
Expand All @@ -61,6 +62,7 @@
:modelValue="values[row.id] || []"
:value="column.id.toString()"
:name="`${row.id}-answer`"
:aria-label="`${row.text}, ${column.text}`"
type="checkbox"
@update:modelValue="
onChangeCheckboxRadio(row.id, $event)
Expand All @@ -70,6 +72,8 @@
<template v-if="questionType === 'number'">
<NcInputField
type="number"
labelOutside
:aria-label="`${row.text}, ${column.text}`"
:modelValue="plainValues[row.id][column.id]"
@update:modelValue="
onChangeTextNumber(
Expand Down
97 changes: 75 additions & 22 deletions src/components/Questions/QuestionLinearScale.vue
Comment thread
Chartman123 marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
type="multiselect"
:clearable="false"
:label="t('forms', 'Lowest value')"
:aria-label-combobox="t('forms', 'Lowest value')"
labelOutside
:options="[0, 1]"
required
Expand All @@ -29,6 +30,7 @@
type="multiselect"
:clearable="false"
:label="t('forms', 'Highest value')"
:aria-label-combobox="t('forms', 'Highest value')"
labelOutside
:options="[2, 3, 4, 5, 6, 7, 8, 9, 10]"
required
Expand All @@ -44,17 +46,24 @@
:class="{
question__content__edit: !readOnly,
}">
<NcTextArea
v-if="!readOnly"
ref="lowest"
:modelValue="optionsLabelLowest"
class="question-linear-scale__label-input"
:label="t('forms', 'Label for lowest value')"
:placeholder="t('forms', 'Label (optional)')"
resize="none"
@input="resizeLabel('lowest')"
@blur="onBlur('lowest')"
@update:modelValue="onOptionsLabelLowestChange" />
<template v-if="!readOnly">
<label
:for="`q${index}__label_lowest_input`"
class="question-linear-scale__label-title question-linear-scale__label-title-lowest">
{{ t('forms', 'Label for lowest value') }}
</label>
<NcTextArea
:id="`q${index}__label_lowest_input`"
ref="lowest"
:modelValue="optionsLabelLowest"
class="question-linear-scale__label-input question-linear-scale__label-input-lowest"
labelOutside
:placeholder="t('forms', 'Label (optional)')"
resize="none"
@input="resizeLabel('lowest')"
@blur="onBlur('lowest')"
@update:modelValue="onOptionsLabelLowestChange" />
</template>
<div
v-else-if="optionsLabelLowest !== ''"
:id="labelId"
Expand Down Expand Up @@ -94,17 +103,24 @@
@keydown.enter.exact.prevent="onKeydownEnter" />
</div>
</fieldset>
<NcTextArea
v-if="!readOnly"
ref="highest"
:modelValue="optionsLabelHighest"
class="question-linear-scale__label-input"
:label="t('forms', 'Label (optional)')"
:aria-label="t('forms', 'Label for highest value')"
resize="none"
@input="resizeLabel('highest')"
@blur="onBlur('highest')"
@update:modelValue="onOptionsLabelHighestChange" />
<template v-if="!readOnly">
<label
:for="`q${index}__label_highest_input`"
class="question-linear-scale__label-title question-linear-scale__label-title-highest">
{{ t('forms', 'Label for highest value') }}
</label>
<NcTextArea
:id="`q${index}__label_highest_input`"
ref="highest"
:modelValue="optionsLabelHighest"
class="question-linear-scale__label-input question-linear-scale__label-input-highest"
labelOutside
:placeholder="t('forms', 'Label (optional)')"
resize="none"
@input="resizeLabel('highest')"
@blur="onBlur('highest')"
@update:modelValue="onOptionsLabelHighestChange" />
</template>
<div
v-else-if="optionsLabelHighest !== ''"
class="question-linear-scale__label question-linear-scale__label-highest">
Expand Down Expand Up @@ -347,6 +363,17 @@ export default defineComponent({

&__edit {
margin-inline-start: -12px;
display: grid;
grid-template-columns: 120px 1fr 120px;
grid-template-areas:
'lowest-title . highest-title'
'lowest options highest';
align-items: center;

@media (max-width: 768px) {
grid-template-columns: 1fr;
grid-template-areas: 'lowest-title' 'lowest' 'options' 'highest-title' 'highest';
}

@media (max-width: 768px) {
margin-inline-end: calc(var(--clickable-area-large) - 2px);
Expand Down Expand Up @@ -383,13 +410,39 @@ export default defineComponent({
min-height: fit-content;
flex-shrink: 0;

&-lowest {
grid-area: lowest;
}

&-highest {
grid-area: highest;
}

@media (max-width: 768px) {
width: 100%; // Full width on smaller screens
padding-block: var(--default-grid-baseline);
}
}

&__label-title {
align-self: end;
margin-bottom: var(--default-grid-baseline);
padding-inline: calc(var(--border-width-input-focused, 2px) + 10px);
font-size: 13px;
font-weight: var(--font-weight-element, 500);
line-height: 1.5;

&-lowest {
grid-area: lowest-title;
}

&-highest {
grid-area: highest-title;
}
}

&__options {
grid-area: options;
width: 100%;
display: flex;
flex-direction: row;
Expand Down
1 change: 1 addition & 0 deletions src/components/Questions/QuestionMultiple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
class="question__item__pseudoInput" />
<input
:placeholder="t('forms', 'Other')"
:aria-label="t('forms', 'Other')"
class="question__input"
:disabled="!readOnly"
:maxlength="maxStringLengths.optionText"
Expand Down
1 change: 1 addition & 0 deletions src/components/SidebarTabs/SettingsSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<div v-show="formExpires && !formArchived" class="settings-div--indent">
<NcDateTimePicker
id="expiresDatetimePicker"
:aria-label="t('forms', 'Expiration date')"
:clearable="false"
:disabled="locked"
:disabledDate="notBeforeToday"
Expand Down
2 changes: 1 addition & 1 deletion src/components/SidebarTabs/SharingSearchDiv.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
:loading="showLoadingCircle"
:disabled="locked || !isCurrentUserOwner"
:options="options"
:placeholder="t('forms', 'Search for user, group or team …')"
:inputLabel="t('forms', 'Search for user, group or team …')"
:aria-label-listbox="t('forms', 'Search for user, group or team …')"
@search="asyncSearch"
@update:modelValue="addShare">
Expand Down
2 changes: 1 addition & 1 deletion src/components/SidebarTabs/TransferOwnership.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
class="modal-content__select"
:loading="loading"
:options="options"
:placeholder="t('forms', 'Search for a user')"
:inputLabel="t('forms', 'Search for a user')"
@search="
(query) => asyncSearch(query, [SHARE_TYPES.SHARE_TYPE_USER])
">
Expand Down
Loading