Skip to content

Commit 63057ed

Browse files
authored
test: add WXT test engineering (#11)
* test: add WXT test engineering * docs: sync Chinese README testing section
1 parent 31628e7 commit 63057ed

18 files changed

Lines changed: 1044 additions & 44 deletions

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ stats.html
1313
stats-*.json
1414
.wxt
1515
web-ext.config.ts
16+
coverage
17+
playwright-report
18+
test-results
1619

1720
# Editor directories and files
1821
.vscode/*

‎README.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ Package extensions:
8080
pnpm zip
8181
```
8282

83+
## Testing
84+
85+
This project uses Vitest for unit/component tests and Playwright for a built-panel smoke test.
86+
87+
```sh
88+
pnpm test
89+
pnpm test:coverage
90+
pnpm test:e2e
91+
```
92+
93+
-`pnpm test` runs fast Vitest tests for pure CSS diff utilities, DOM style formatting, and the Vue DevTools panel shell.
94+
-`pnpm test:coverage` generates local coverage output under `coverage/`.
95+
-`pnpm test:e2e` builds the Chrome extension first, then serves `.output/chrome-mv3` locally and verifies that the built DevTools panel renders.
96+
8397
## Tech Stack
8498

8599
-[WXT](https://wxt.dev/) for browser extension development

‎README.zh-CN.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ pnpm build:edge
8080
pnpm zip
8181
```
8282

83+
## 测试
84+
85+
本项目使用 Vitest 进行单元/组件测试,并使用 Playwright 对构建后的面板做冒烟测试。
86+
87+
```sh
88+
pnpm test
89+
pnpm test:coverage
90+
pnpm test:e2e
91+
```
92+
93+
-`pnpm test` 会运行快速 Vitest 测试,覆盖 CSS diff 纯工具、DOM 样式格式化和 Vue DevTools 面板外壳。
94+
-`pnpm test:coverage` 会在本地 `coverage/` 目录下生成覆盖率报告。
95+
-`pnpm test:e2e` 会先构建 Chrome 扩展,然后在本地服务 `.output/chrome-mv3` 并验证构建后的 DevTools 面板可以正常渲染。
96+
8397
## 技术栈
8498

8599
-[WXT](https://wxt.dev/) 用于浏览器扩展开发

‎entrypoints/devtools-panel/hooks/useDevToolsPanel.ts‎

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useClipboard } from '@vueuse/core'
33
import{ElMessage}from'element-plus'
44
import{t}from'../lang'
55
importSMfrom'../message'
6-
import{formatStyle,typeFormatStyleValue}from'../utils'
6+
import{compareStyles,formatStyle,typeFormatStyleValue,getVisibleCssDiffs}from'../utils'
77

88
exportfunctionuseDevToolsPanel(){
99
constinputValue=ref('')
@@ -83,40 +83,17 @@ export function useDevToolsPanel() {
8383
functioncompareSelectedEl(){
8484
const[{style: styles1={}},{style: styles2={}}]=selectedEl
8585

86-
constdiffs: Array<CssDiffsType>=[]
87-
88-
constallProperties=newSet([
89-
...Object.keys(styles1),
90-
...Object.keys(styles2),
91-
])
92-
93-
allProperties.forEach((property)=>{
94-
constleft=styles1[property]||'未定义'
95-
constright=styles2[property]||'未定义'
96-
97-
diffs.push({
98-
property,
99-
left,
100-
right,
101-
isDiff: left!==right,
102-
})
103-
})
104-
105-
cssDiffs.push(...diffs)
86+
cssDiffs.length=0
87+
cssDiffs.push(...compareStyles(styles1,styles2))
10688
}
10789

10890
constrenderCssDiffs=computed(()=>{
109-
returninputValueFilter(isAllProperty.value
110-
? cssDiffs
111-
: cssDiffs.filter(css=>css.isDiff),inputValue.value)
91+
returngetVisibleCssDiffs(cssDiffs,{
92+
isAllProperty: isAllProperty.value,
93+
inputValue: inputValue.value,
94+
})
11295
})
11396

114-
functioninputValueFilter(cssDiffs: Array<CssDiffsType>,inputValue: string){
115-
return!inputValue
116-
? cssDiffs
117-
: cssDiffs.filter(c=>c.property.includes(inputValue))
118-
}
119-
12097
functiononTableCellClassName({ columnIndex }: {columnIndex: number}){
12198
return!columnIndex ? 'text-[var(--el-table-text-color)] cursor-auto' : ''
12299
}

‎entrypoints/devtools-panel/message.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ class SendMessage {
1313
privateasyncinit(){
1414
const[currentTab]=awaitbrowser.tabs.query({active: true})
1515

16-
this.currentTabId=currentTab.id!
16+
this.currentTabId=currentTab?.id
1717
}
1818

1919
publicasyncsend(data: Array<SelectedElType>){
2020
constwindows=awaitbrowser.windows.getAll({populate: true});
2121

2222
(windowsasunknownasArray<_Window>).forEach((window)=>{
2323
for(consttabofwindow.tabs){
24-
if(tab.id!==this.currentTabId){
24+
if(tab.id!=null&&tab.id!==this.currentTabId){
2525
// Send selected data to other windows/tabs
2626
browser.tabs.sendMessage(
27-
tab.id!,
27+
tab.id,
2828
data,
2929
)
3030
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
importtype{CssDiffsType}from'../types'
2+
3+
exporttypeCssStyleRecord=Record<string,string|null|undefined>
4+
5+
constMISSING_STYLE_VALUE='未定义'
6+
7+
functionnormalizeStyleValue(value: string|null|undefined){
8+
returnvalue||MISSING_STYLE_VALUE
9+
}
10+
11+
exportfunctioncompareStyles(
12+
leftStyles: CssStyleRecord={},
13+
rightStyles: CssStyleRecord={},
14+
): Array<CssDiffsType>{
15+
constallProperties=newSet([
16+
...Object.keys(leftStyles),
17+
...Object.keys(rightStyles),
18+
])
19+
20+
returnArray.from(allProperties,(property)=>{
21+
constleft=normalizeStyleValue(leftStyles[property])
22+
constright=normalizeStyleValue(rightStyles[property])
23+
24+
return{
25+
property,
26+
left,
27+
right,
28+
isDiff: left!==right,
29+
}
30+
})
31+
}
32+
33+
exportfunctiongetVisibleCssDiffs(
34+
cssDiffs: Array<CssDiffsType>,
35+
{
36+
isAllProperty,
37+
inputValue,
38+
}: {
39+
isAllProperty: boolean
40+
inputValue: string
41+
},
42+
): Array<CssDiffsType>{
43+
constsource=isAllProperty
44+
? cssDiffs
45+
: cssDiffs.filter(css=>css.isDiff)
46+
47+
returninputValue
48+
? source.filter(css=>css.property.includes(inputValue))
49+
: [...source]
50+
}

‎entrypoints/devtools-panel/utils/formatStyle.ts‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@ export interface FormatStyleValue {
22
tag: string
33
id?: string
44
class?: string
5-
style?: Record<string,any>
5+
style?: Record<string,string>
66
}
77

8-
exportfunctionformatStyle(element: Element): FormatStyleValue|null{
8+
exportfunctionformatStyle(element: Element|null): FormatStyleValue|null{
99
if(!element){
1010
returnnull
1111
}
1212

1313
conststyles=(elementasNode)?.ownerDocument?.defaultView?.getComputedStyle(element)
14-
constoutValue: Record<string,any>={}
14+
constoutValue: Record<string,string>={}
1515

1616
if(styles){
17-
for(leti=0;i<=styles.length;i++){
18-
constStyleKey=styles[i]
19-
constStyleValue=styles.getPropertyValue(StyleKey)
20-
outValue[StyleKey]=StyleValue
17+
for(leti=0;i<styles.length;i++){
18+
conststyleKey=styles[i]
19+
20+
if(styleKey){
21+
outValue[styleKey]=styles.getPropertyValue(styleKey)
22+
}
2123
}
2224
}
2325

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export*from'./array'
2+
export*from'./cssDiff'
23
export*from'./formatStyle'

‎package.json‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
"zip:firefox": "wxt zip -b firefox --mv3",
1919
"zip:edge": "wxt zip -b edge",
2020
"compile": "vue-tsc --noEmit",
21+
"test": "pnpm test:unit",
22+
"test:unit": "vitest run",
23+
"test:watch": "vitest",
24+
"test:coverage": "vitest run --coverage",
25+
"test:e2e": "pnpm build:chrome && playwright test",
2126
"postinstall": "wxt prepare",
2227
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
2328
},
@@ -28,14 +33,20 @@
2833
},
2934
"devDependencies": {
3035
"@antfu/eslint-config": "^3.12.0",
36+
"@playwright/test": "^1.60.0",
3137
"@tailwindcss/vite": "^4.3.0",
3238
"@types/chrome": "^0.0.280",
39+
"@vitejs/plugin-vue": "^6.0.6",
40+
"@vitest/coverage-v8": "^4.1.6",
41+
"@vue/test-utils": "^2.4.10",
3342
"@vueuse/core": "^12.0.0",
3443
"@wxt-dev/module-vue": "^1.0.3",
3544
"conventional-changelog-cli": "^5.0.0",
3645
"eslint": "^9.17.0",
46+
"happy-dom": "^20.9.0",
3747
"tailwindcss": "^4.3.0",
3848
"typescript": "5.6.3",
49+
"vitest": "^4.1.6",
3950
"vue-tsc": "^2.1.10",
4051
"wxt": "^0.20.26"
4152
}

‎playwright.config.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import{existsSync}from'node:fs'
2+
importprocessfrom'node:process'
3+
import{defineConfig}from'@playwright/test'
4+
5+
constchromiumExecutablePath=[
6+
process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,
7+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
8+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
9+
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
10+
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
11+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
12+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
13+
'/usr/bin/google-chrome',
14+
'/usr/bin/chromium',
15+
'/usr/bin/chromium-browser',
16+
].find((value): value is string=>Boolean(value&&existsSync(value)))
17+
18+
exportdefaultdefineConfig({
19+
testDir: './tests/e2e',
20+
timeout: 60_000,
21+
expect: {
22+
timeout: 5_000,
23+
},
24+
fullyParallel: false,
25+
reporter: 'list',
26+
use: {
27+
browserName: 'chromium',
28+
launchOptions: chromiumExecutablePath
29+
? {executablePath: chromiumExecutablePath}
30+
: undefined,
31+
trace: 'retain-on-failure',
32+
},
33+
})

0 commit comments

Comments
 (0)