Skip to content

Commit cb3a680

Browse files
committed
feat: add vitest for testing, update pnpm workspace, and implement component tests
1 parent 327e263 commit cb3a680

21 files changed

Lines changed: 1542 additions & 25 deletions

‎.github/workflows/test.yml‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
concurrency:
15+
group: test-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
test:
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 15
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Install pnpm
27+
uses: pnpm/action-setup@v4.1.0
28+
29+
- name: Install Node.js
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: 24
33+
cache: 'pnpm'
34+
35+
- run: pnpm install --frozen-lockfile
36+
37+
- name: Build
38+
run: pnpm build
39+
40+
- name: Lint
41+
run: pnpm lint
42+
43+
- name: Test
44+
run: pnpm test

‎package.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"watch": "pnpm run \"/^watch:.*/\"",
77
"watch:base": "tsc -b -w",
88
"watch:vscode": "pnpm -F mpx-official run watch",
9-
"test": "vitest",
9+
"test": "vitest run",
10+
"test:watch": "vitest",
1011
"lint": "eslint --cache .",
1112
"format": "prettier --write --cache .",
1213
"clean": "rimraf -g .eslintcache \"**/*.tsbuildinfo\" && pnpm clean:out",
@@ -44,6 +45,7 @@
4445
"rimraf": "^6.0.1",
4546
"simple-git-hooks": "^2.9.0",
4647
"tsx": "^4.19.3",
47-
"typescript": "catalog:"
48+
"typescript": "catalog:",
49+
"vitest": "catalog:"
4850
}
4951
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Tests
2+
3+
Run all tests once with `pnpm test`, or keep Vitest running with
4+
`pnpm test:watch`.
5+
6+
The test suite has three layers:
7+
8+
- `language-core` fixtures create the real Mpx/Volar/TypeScript language
9+
service and assert generated code, diagnostics, hover information, and
10+
definitions.
11+
- `language-service` tests isolate request concurrency and mock only the HTML
12+
service and template lookup boundary.
13+
- `inspect-extension` remains the manual integration project for validating
14+
the final editor UI and extension packaging.
15+
16+
Feature fixtures live under `fixtures/`. Keep them small and local to the
17+
behavior under test; do not make unit tests depend on generated `out` files or
18+
the mutable `inspect-extension` project.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts">
2+
import { createComponent } from '@mpxjs/core'
3+
4+
createComponent({
5+
properties: {
6+
value: String,
7+
optionsText: String,
8+
},
9+
})
10+
</script>
11+
12+
<script name="json">
13+
module.exports = {
14+
component: true,
15+
}
16+
</script>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
value: number
4+
setupCount?: number
5+
}>()
6+
defineExpose({})
7+
</script>
8+
9+
<script name="json">
10+
module.exports = {
11+
component: true,
12+
}
13+
</script>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script lang="ts">
2+
import { createComponent } from '@mpxjs/core'
3+
4+
createComponent({
5+
properties: {
6+
directoryCount: Number,
7+
},
8+
})
9+
</script>
10+
11+
<script name="json">
12+
module.exports = {
13+
component: true,
14+
}
15+
</script>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<template>
2+
<view>{{ stableText.toUpperCase() }}</view>
3+
<view>{{ isV80 ? formatCount(localCount) : 'legacy' }}</view>
4+
<view>{{ homeVersion.toFixed(0) }}</view>
5+
</template>
6+
7+
<script lang="ts">
8+
import { createComponent } from '@mpxjs/core'
9+
10+
const mappedGetters = {
11+
isV80() {
12+
return true
13+
},
14+
} as {
15+
isV80(): boolean
16+
homeVersion(): 'homepagemarketing' | 'homepageonestop'
17+
}
18+
19+
createComponent({
20+
data: {
21+
localCount: 1,
22+
},
23+
properties: {
24+
stableText: String,
25+
homeVersion: Number,
26+
},
27+
computed: {
28+
...mappedGetters,
29+
},
30+
methods: {
31+
formatCount(value: number) {
32+
return value.toFixed(0)
33+
},
34+
},
35+
})
36+
</script>
37+
38+
<script name="json">
39+
module.exports = {
40+
component: true,
41+
}
42+
</script>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script>
2+
import { createComponent } from '@mpxjs/core'
3+
4+
createComponent({
5+
properties: {
6+
jsText: String,
7+
},
8+
})
9+
</script>
10+
11+
<script name="json">
12+
module.exports = {
13+
component: true,
14+
}
15+
</script>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<template>
2+
<view>{{ parentText }}</view>
3+
</template>
4+
5+
<script lang="ts">
6+
import { createComponent, type PropType } from '@mpxjs/core'
7+
8+
interface UserProfile {
9+
/** 用户唯一 ID。 */
10+
id: number
11+
12+
/** 用户展示名称。 */
13+
name: string
14+
}
15+
16+
createComponent({
17+
properties: {
18+
/**
19+
* 旧版简短文案。
20+
*
21+
* @deprecated 请改用 parentText。
22+
*/
23+
shortText: String,
24+
25+
/**
26+
* 父组件传入的主文案。
27+
*
28+
* @default 'hello'
29+
*/
30+
parentText: {
31+
type: String,
32+
value: 'hello',
33+
},
34+
35+
/** 用于演示 Number 属性的数值。 */
36+
name: {
37+
type: Number,
38+
},
39+
40+
/** 当前用户资料。 */
41+
profile: {
42+
type: Object as PropType<UserProfile>,
43+
},
44+
45+
/** 组件显示主题。 */
46+
theme: String as PropType<'light' | 'dark'>,
47+
},
48+
})
49+
</script>
50+
51+
<script name="json">
52+
module.exports = {
53+
component: true,
54+
}
55+
</script>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<template>
2+
<component-options
3+
parentText="{{ 123 }}"
4+
shortText="{{ 123 }}"
5+
name="{{ 'hello' }}"
6+
profile="{{ 'invalid-profile' }}"
7+
/>
8+
<component-options
9+
name@ios|android|harmony="{{ 'hello' }}"
10+
parentText@_wx="{{ 123 }}"
11+
/>
12+
<component-options
13+
name@ios="{{ 'hello' }}"
14+
name@android="{{ 2 }}"
15+
/>
16+
<component-options
17+
bindtap="handleTap"
18+
catchtap="handleTap"
19+
catch:tap="handleTap"
20+
/>
21+
<component-options profile="{{ { } }}" />
22+
<component-options-js jsText="{{ 123 }}" />
23+
<component-index directoryCount="{{ 'hello' }}" />
24+
<component-options-inference-conflict stableText="{{ 123 }}" />
25+
</template>
26+
27+
<script lang="ts">
28+
import ComponentOptions, { createComponent } from '@mpxjs/core'
29+
30+
void ComponentOptions
31+
32+
createComponent({
33+
methods: {
34+
handleTap() {},
35+
},
36+
})
37+
</script>
38+
39+
<script type="application/json">
40+
{
41+
"component": true,
42+
"usingComponents": {
43+
"component-options": "./component-options",
44+
"component-index": "./component-index",
45+
"component-options-inference-conflict": "./component-options-inference-conflict.mpx",
46+
"component-options-js": "./component-options-js.mpx"
47+
}
48+
}
49+
</script>

0 commit comments

Comments
 (0)