Skip to content

Commit cfab131

Browse files
authored
Merge pull request #1267 from nextcloud-libraries/chore/more-vue-tests
test(vue3): add some formatting tests
2 parents 0ccb35e + 9ce9877 commit cfab131

File tree

5 files changed

+147
-19
lines changed

5 files changed

+147
-19
lines changed

tests/config-codestyle.test.ts

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import type { Linter } from 'eslint'
66

77
import { ESLint } from 'eslint'
8-
import { existsSync } from 'fs'
98
import { readFile } from 'fs/promises'
109
import { join, resolve } from 'path'
1110
import { expect, test } from 'vitest'
@@ -24,29 +23,24 @@ const eslint = new ESLint({
2423
* @return Lint result
2524
*/
2625
async function lintTestCase(testCase: string) {
27-
let file = `fixtures/codestyle/input/${testCase}.`
28-
if (existsSync(join(__dirname, file) + 'js')) {
29-
file += 'js'
30-
} else {
31-
file += 'ts'
32-
}
33-
34-
const path = resolve(join(__dirname, file))
26+
const filepath = join('fixtures/codestyle/input/', testCase)
27+
const path = resolve(join(__dirname, filepath))
3528
const content = await readFile(path)
36-
const results = await eslint.lintText(content.toString(), { filePath: `src/${file}` })
29+
const results = await eslint.lintText(content.toString(), { filePath: `src/${filepath}` })
3730
return { results, path }
3831
}
3932

4033
test.for([
41-
'array',
42-
'arrow-function',
43-
'function',
44-
'exports',
45-
'imports',
46-
'indention',
47-
'objects',
48-
'quotes',
49-
'semicolons',
34+
'array.js',
35+
'arrow-function.ts',
36+
'exports.ts',
37+
'function.ts',
38+
'imports.ts',
39+
'indention.js',
40+
'objects.js',
41+
'quotes.js',
42+
'semicolons.js',
43+
'VueComponent.vue',
5044
])('Code style', async (testCase: string) => {
5145
const { results, path } = await lintTestCase(testCase)
5246
expect(results).toHaveLength(1)

tests/config-vue.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import type { Linter } from 'eslint'
7+
8+
import { ESLint } from 'eslint'
9+
import { readFile } from 'fs/promises'
10+
import { join, resolve } from 'path'
11+
import { expect, test } from 'vitest'
12+
import * as eslintConfig from '../lib/index.js'
13+
14+
const eslint = new ESLint({
15+
overrideConfigFile: true,
16+
overrideConfig: eslintConfig.recommended as Linter.Config<Linter.RulesRecord>[],
17+
})
18+
19+
/**
20+
* Lint a file with ESLint
21+
*
22+
* @param file - File path to lint
23+
* @return Lint result
24+
*/
25+
async function lintFile(file: string) {
26+
const real = resolve(join(__dirname, file))
27+
const content = await readFile(real)
28+
return await eslint.lintText(content.toString(), { filePath: join('src', file) })
29+
}
30+
31+
test('Formatting', async () => {
32+
const results = await lintFile('fixtures/component-formatting.vue')
33+
expect(results).toHaveIssueCount(3)
34+
expect(results).toHaveIssue({
35+
ruleId: 'vue/prop-name-casing',
36+
line: 11,
37+
})
38+
expect(results).toHaveIssue({
39+
ruleId: 'vue/custom-event-name-casing',
40+
line: 31,
41+
})
42+
expect(results).toHaveIssue({
43+
ruleId: 'vue/slot-name-casing',
44+
line: 34,
45+
})
46+
})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<script lang="ts">
7+
import NcComponent from './NcComponent.vue'
8+
9+
export default {
10+
name: 'my-app', // ❌ Should be PascalCase 'MyApp'
11+
12+
components: {
13+
'nc-component': NcComponent, // ❌ Should be PascalCase 'NcComponent'
14+
},
15+
}
16+
</script>
17+
18+
<template>
19+
<div>
20+
<nc-component /> <!-- ❌ Should be PascalCase <NcComponent /> -->
21+
<NcComponent></NcComponent> <!-- ❌ Should be an empty tag <NcComponent /> -->
22+
<NcComponent @update:model-value="console.log" /> <!-- ❌ Should be camelCase 'update:modelValue' -->
23+
<NcComponent :component-prop="42" /> <!-- ❌ Should be camelCase 'componentProp' -->
24+
<NcComponent aria-label="Label" data-testid="test" /> <!-- ✅ Data and ARIA attributes are allowed to be in kebab-case -->
25+
</div>
26+
</template>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<script lang="ts">
7+
import NcComponent from './NcComponent.vue'
8+
9+
export default {
10+
name: 'MyApp', // ❌ Should be PascalCase 'MyApp'
11+
12+
components: {
13+
NcComponent, // ❌ Should be PascalCase 'NcComponent'
14+
},
15+
}
16+
</script>
17+
18+
<template>
19+
<div>
20+
<NcComponent /> <!-- ❌ Should be PascalCase <NcComponent /> -->
21+
<NcComponent /> <!-- ❌ Should be an empty tag <NcComponent /> -->
22+
<NcComponent @update:modelValue="console.log" /> <!-- ❌ Should be camelCase 'update:modelValue' -->
23+
<NcComponent :componentProp="42" /> <!-- ❌ Should be camelCase 'componentProp' -->
24+
<NcComponent aria-label="Label" data-testid="test" /> <!-- ✅ Data and ARIA attributes are allowed to be in kebab-case -->
25+
</div>
26+
</template>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<script setup lang="ts">
7+
import type { Slot } from 'vue'
8+
9+
defineProps<{
10+
// eslint-disable-next-line vue/no-unused-properties
11+
'component-prop': number // ❌ Should be camelCase 'componentProp'
12+
}>()
13+
14+
// Note: vue/custom-event-name-casing only checks emit/$emit calls, not event definitions
15+
const emit = defineEmits<{
16+
'my-event': []
17+
'namespace:event': []
18+
'update:model-value': [value: unknown]
19+
}>()
20+
21+
// Note: vue/slot-name-casing only checks name in <slot name> in template, not slot definitions
22+
defineSlots<{
23+
'my-icon': Slot
24+
}>()
25+
26+
emit('update:model-value', 'value') // ❌ Should be camelCase 'update:modelValue'
27+
</script>
28+
29+
<template>
30+
<div>
31+
<button @click="$emit('my-event')" /> <!-- ❌ Should be camelCase 'myEvent' -->
32+
<button @click="$emit('namespace:event')" /> <!-- ✅ Namespaced events are allowed -->
33+
<button @click="$emit('update:model-value')" /> <!-- ⚠️ vue/custom-event-name-casing ignores update:* events completely -->
34+
<slot name="my-icon" /> <!-- ❌ Should be camelCase 'myIcon' -->
35+
</div>
36+
</template>

0 commit comments

Comments
 (0)