diff --git a/packages/coverage-istanbul/src/provider.ts b/packages/coverage-istanbul/src/provider.ts index 3bc5c78f5b32..08af60ee9f9e 100644 --- a/packages/coverage-istanbul/src/provider.ts +++ b/packages/coverage-istanbul/src/provider.ts @@ -79,6 +79,8 @@ export class IstanbulCoverageProvider implements CoverageProvider { return const sourceMap = pluginCtx.getCombinedSourcemap() + sourceMap.sources = sourceMap.sources.map(removeQueryParameters) + const code = this.instrumenter.instrumentSync(sourceCode, id, sourceMap as any) const map = this.instrumenter.lastSourceMap() as any @@ -227,3 +229,12 @@ function resolveIstanbulOptions(options: CoverageIstanbulOptions, root: string) return resolved as ResolvedCoverageOptions & { provider: 'istanbul' } } + +/** + * Remove possible query parameters from filenames + * - From `/src/components/Header.component.ts?vue&type=script&src=true&lang.ts` + * - To `/src/components/Header.component.ts` + */ +function removeQueryParameters(filename: string) { + return filename.split('?')[0] +} diff --git a/test/coverage-test/coverage-test/coverage.istanbul.test.ts b/test/coverage-test/coverage-test/coverage.istanbul.test.ts index 45d58fd6a521..46780cd9e5c7 100644 --- a/test/coverage-test/coverage-test/coverage.istanbul.test.ts +++ b/test/coverage-test/coverage-test/coverage.istanbul.test.ts @@ -3,7 +3,7 @@ import { resolve } from 'pathe' import { expect, test } from 'vitest' test('istanbul html report', async () => { - const coveragePath = resolve('./coverage') + const coveragePath = resolve('./coverage/src') const files = fs.readdirSync(coveragePath) expect(files).toContain('index.html') @@ -24,8 +24,18 @@ test('istanbul lcov report', async () => { }) test('all includes untested files', () => { - const coveragePath = resolve('./coverage') + const coveragePath = resolve('./coverage/src') const files = fs.readdirSync(coveragePath) expect(files).toContain('untested-file.ts.html') }) + +test('files should not contain query parameters', () => { + const coveragePath = resolve('./coverage/src/Counter') + const files = fs.readdirSync(coveragePath) + + expect(files).toContain('index.html') + expect(files).toContain('Counter.vue.html') + expect(files).toContain('Counter.component.ts.html') + expect(files).not.toContain('Counter.component.ts?vue&type=script&src=true&lang.ts.html') +}) diff --git a/test/coverage-test/src/Counter/Counter.component.ts b/test/coverage-test/src/Counter/Counter.component.ts new file mode 100644 index 000000000000..86cc4db9cbb1 --- /dev/null +++ b/test/coverage-test/src/Counter/Counter.component.ts @@ -0,0 +1,21 @@ +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + name: 'Counter', + + setup() { + const count = ref(0) + return { count } + }, + + methods: { + uncoveredMethod() { + return 'This line should not be covered' + }, + + coveredMethod() { + return 'This line should be covered' + }, + }, +}) + diff --git a/test/coverage-test/src/Counter/Counter.vue b/test/coverage-test/src/Counter/Counter.vue new file mode 100644 index 000000000000..601de54b7689 --- /dev/null +++ b/test/coverage-test/src/Counter/Counter.vue @@ -0,0 +1,15 @@ + + + + diff --git a/test/coverage-test/src/Counter/index.ts b/test/coverage-test/src/Counter/index.ts new file mode 100644 index 000000000000..378476d78d22 --- /dev/null +++ b/test/coverage-test/src/Counter/index.ts @@ -0,0 +1,4 @@ +import CounterComponent from './Counter.component' +import CounterVue from './Counter.vue' + +export { CounterComponent, CounterVue } diff --git a/test/coverage-test/test/vue.test.ts b/test/coverage-test/test/vue.test.ts index 1dd265ca61ea..171e11c1aadc 100644 --- a/test/coverage-test/test/vue.test.ts +++ b/test/coverage-test/test/vue.test.ts @@ -6,6 +6,7 @@ import { expect, test } from 'vitest' import { mount } from '@vue/test-utils' import Hello from '../src/Hello.vue' import Defined from '../src/Defined.vue' +import { CounterVue } from '../src/Counter' test('vue 3 coverage', async () => { expect(Hello).toBeTruthy() @@ -35,3 +36,10 @@ test('define package in vm', () => { expect(wrapper.text()).toContain(MY_CONSTANT) }) + +test('vue non-SFC, uses query parameters in file imports', async () => { + const wrapper = mount(CounterVue) + + await wrapper.find('button').trigger('click') + expect(wrapper.text()).contain(1) +})