Skip to content

Commit 262c9f8

Browse files
committed
fix(settings): improve forced locale/language validation and testability
- Clarified the naming in the validate functions - Removed unnecessary mocks, and added stubs in tests. - Testing for existence of element with data-test attributes, and without relying on translated text. - Removed overly complex component mocking Signed-off-by: Annabel Church <215145+arc64@users.noreply.github.com>
1 parent 9ff3f60 commit 262c9f8

File tree

7 files changed

+216
-321
lines changed

7 files changed

+216
-321
lines changed

apps/settings/lib/Settings/Personal/PersonalInfo.php

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,20 @@ function (IAccountProperty $property) {
228228
* Validates a forced language setting against available languages
229229
*/
230230
private function validateForcedLanguage(string $forcedLanguage, array $languages): ?array {
231-
$allLanguages = array_merge($languages['commonLanguages'], $languages['otherLanguages']);
232-
$forcedLang = array_filter($allLanguages, fn($lang) => $lang['code'] === $forcedLanguage);
233-
$forcedLang = reset($forcedLang);
234-
235-
if ($forcedLang && isset($forcedLang['name'])) {
231+
$allLanguages = array_merge(
232+
$languages['commonLanguages'] ?? [],
233+
$languages['otherLanguages'] ?? []
234+
);
235+
$matchingLanguages = array_filter(
236+
$allLanguages,
237+
fn($lang) => $lang['code'] === $forcedLanguage
238+
);
239+
$matchingLanguage = reset($matchingLanguages);
240+
241+
if ($matchingLanguage && isset($matchingLanguage['name'])) {
236242
return [
237243
'code' => $forcedLanguage,
238-
'name' => $forcedLang['name']
244+
'name' => $matchingLanguage['name']
239245
];
240246
}
241247

@@ -288,13 +294,16 @@ private function getLanguageMap(IUser $user): array {
288294
* Validates a forced locale setting against available locales
289295
*/
290296
private function validateForcedLocale(string $forcedLocale, array $localeCodes): ?array {
291-
$forcedLocaleObj = array_filter($localeCodes, fn($locale) => $locale['code'] === $forcedLocale);
292-
$forcedLocaleObj = reset($forcedLocaleObj);
293-
294-
if ($forcedLocaleObj && isset($forcedLocaleObj['name'])) {
297+
$matchingLocales = array_filter(
298+
$localeCodes,
299+
fn($locale) => $locale['code'] === $forcedLocale
300+
);
301+
$matchingLocale = reset($matchingLocales);
302+
303+
if ($matchingLocale && isset($matchingLocale['name'])) {
295304
return [
296305
'code' => $forcedLocale,
297-
'name' => $forcedLocaleObj['name']
306+
'name' => $matchingLocale['name']
298307
];
299308
}
300309

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { mount } from '@vue/test-utils'
2+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
3+
import { loadState } from '@nextcloud/initial-state'
4+
import LanguageSection from './LanguageSection.vue'
5+
6+
/**
7+
* Mock Nextcloud modules
8+
*/
9+
vi.mock('@nextcloud/initial-state', () => ({
10+
loadState: vi.fn(() => ({
11+
languageMap: {
12+
activeLanguage: { code: 'en', name: 'English' },
13+
commonLanguages: [],
14+
otherLanguages: [],
15+
},
16+
})),
17+
}))
18+
19+
describe('LanguageSection', () => {
20+
let wrapper
21+
22+
const mountComponent = () => {
23+
return mount(LanguageSection, {
24+
stubs: {
25+
Language: {
26+
template: '<div data-test="language-select" />',
27+
},
28+
HeaderBar: {
29+
template: '<div data-test="header-bar" />',
30+
},
31+
},
32+
})
33+
}
34+
35+
describe('when the language is user-configurable', () => {
36+
beforeEach(async () => {
37+
const userConfigurableData = {
38+
languageMap: {
39+
activeLanguage: { code: 'en', name: 'English' },
40+
commonLanguages: [{ code: 'en', name: 'English' }],
41+
otherLanguages: [{ code: 'de', name: 'German' }],
42+
},
43+
}
44+
vi.mocked(loadState).mockReturnValueOnce(userConfigurableData)
45+
wrapper = mountComponent()
46+
await wrapper.vm.$nextTick()
47+
})
48+
49+
it('shows the language select component', () => {
50+
expect(wrapper.find('[data-test="language-select"]').exists()).toBe(true)
51+
})
52+
53+
})
54+
55+
describe('when there is no language data', () => {
56+
beforeEach(async () => {
57+
const noLanguageData = { languageMap: {} }
58+
vi.mocked(loadState).mockReturnValueOnce(noLanguageData)
59+
wrapper = mountComponent()
60+
await wrapper.vm.$nextTick()
61+
})
62+
63+
it('shows no language component', () => {
64+
expect(wrapper.find('[data-test="no-language-message"]').exists()).toBe(true)
65+
})
66+
})
67+
68+
describe('when the language is forced by the administrator', () => {
69+
beforeEach(async () => {
70+
const forcedLanguageData = {
71+
languageMap: {
72+
forcedLanguage: { code: 'uk', name: 'Ukrainian' },
73+
},
74+
}
75+
vi.mocked(loadState).mockReturnValueOnce(forcedLanguageData)
76+
wrapper = mountComponent()
77+
await wrapper.vm.$nextTick()
78+
})
79+
80+
it('shows forced language component', () => {
81+
expect(wrapper.find('[data-test="forced-language-message"]').exists()).toBe(true)
82+
})
83+
84+
})
85+
86+
afterEach(() => {
87+
if (wrapper) {
88+
wrapper.destroy()
89+
wrapper = null
90+
}
91+
vi.resetAllMocks()
92+
})
93+
})

apps/settings/src/components/PersonalInfo/LanguageSection/LanguageSection.vue

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
:readable="propertyReadable" />
1010

1111
<Language v-if="isEditable"
12+
data-test="language-select"
1213
:input-id="inputId"
1314
:common-languages="commonLanguages"
1415
:other-languages="otherLanguages"
1516
:language.sync="language" />
1617

17-
<span v-else-if="forcedLanguage && forcedLanguage.name">
18+
<span v-else-if="forcedLanguage && forcedLanguage.name"
19+
data-test="forced-language-message">
1820
{{ t('settings', 'Language is forced to {language} by the administrator', { language: forcedLanguage.name }) }}
1921
</span>
20-
<span v-else>
22+
<span v-else
23+
data-test="no-language-message">
2124
{{ t('settings', 'No language set') }}
2225
</span>
2326
</section>
@@ -76,8 +79,7 @@ export default {
7679
7780
methods: {
7881
t,
79-
}
80-
82+
},
8183
}
8284
</script>
8385

apps/settings/src/components/PersonalInfo/LanguageSection/__tests__/LanguageSection.spec.js

Lines changed: 0 additions & 152 deletions
This file was deleted.

0 commit comments

Comments
 (0)