Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/detail.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ simulate.load('/comp', 'custom-comp') // 渲染出来的结果是 <comp><wx-view
}
```

这种绝对路径写法的,它会从我们提供的根路径开始寻找对应组件;但是使用相对路径写法,则无需做任何处理:
这种绝对路径写法的,它会从我们提供的根路径开始寻找对应组件;未指定 rootPath 时(默认取 load 传入组件所在目录)如果从该目录找不到,则会从组件所在目录逐级往上查找,取最近的一个存在的组件路径,此时编译根路径也会同步调整为二者的公共父路径;但是使用相对路径写法,则无需做任何处理:

```json
{
Expand Down
4 changes: 4 additions & 0 deletions docs/update.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# 更新日志

## 1.6.3

* 修复 usingComponents 中绝对路径引入的嵌套组件在未指定 rootPath 时渲染为空节点的问题

## 1.6.2 & 依赖 j-component 更新 1.4.10

* 修复 setData 触发事件重新监听进而导致逻辑陷入死循环的问题
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "miniprogram-simulate",
"version": "1.6.2",
"version": "1.6.3",
"description": "tools for miniprogram custom component unit test",
"main": "index.js",
"types": "index.d.ts",
Expand Down
55 changes: 53 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,55 @@ function behavior(definition) {
return jComponent.behavior(definition)
}

/**
* 获取两个路径的公共父路径
*/
function getCommonAncestorPath(pathA, pathB) {
const listA = path.resolve(pathA).split(path.sep)
const listB = path.resolve(pathB).split(path.sep)
const commonList = []

for (let i = 0, len = Math.min(listA.length, listB.length); i < len; i++) {
if (listA[i] !== listB[i]) break
commonList.push(listA[i])
}

return commonList.join(path.sep) || path.sep
}

/**
* 计算 usingComponents 中某个依赖组件对应的路径
*/
function resolveUsingComponentsPath(value, componentPath, cache) {
if (!_.isAbsolute(value)) {
// 相对路径,以当前组件所在目录为基准
return path.join(path.dirname(componentPath), value)
}

// 绝对路径,以 rootPath 为基准
const rootPath = cache.options.rootPath
const usingPath = path.join(rootPath, value)
if (_.readFile(`${usingPath}.json`)) return usingPath
if (!cache.rootPathIsDefault) return usingPath

// rootPath 未指定时其默认值为当前组件所在目录,此时无法得知项目根路径,
// 对于以项目根路径为基准书写的绝对路径会解析失败,导致该组件被当作空节点渲染,
// 因此再从组件所在目录逐级向上查找,取最近的一个存在的组件路径
let dir = path.dirname(componentPath)
while (dir !== path.dirname(dir)) {
const dirPath = path.join(dir, value)
if (_.readFile(`${dirPath}.json`)) {
// 找到的组件可能不在原 rootPath 下,需要同步扩大编译根路径,否则无法编译其模板
cache.options.rootPath = getCommonAncestorPath(cache.options.rootPath, dirPath)
return dirPath
}

dir = path.dirname(dir)
}

return usingPath
}

/* eslint-disable complexity */
/**
* 注册自定义组件
Expand Down Expand Up @@ -102,7 +151,6 @@ function register(componentPath, tagName, cache, hasRegisterCache) {
}

// 先加载 using components
const rootPath = cache.options.rootPath
const usingComponents = component.json.usingComponents || {}
const overrideUsingComponents = cache.options.usingComponents || {}
Object.assign(usingComponents, overrideUsingComponents)
Expand All @@ -111,7 +159,7 @@ function register(componentPath, tagName, cache, hasRegisterCache) {
const key = usingComponentKeys[i]

const value = usingComponents[key]
const usingPath = _.isAbsolute(value) ? path.join(rootPath, value) : path.join(path.dirname(componentPath), value)
const usingPath = resolveUsingComponentsPath(value, componentPath, cache)

if (_.readFile(`${usingPath}.json`)) {
// 文件路径
Expand Down Expand Up @@ -145,6 +193,8 @@ function load(componentPath, tagName, options = {}) {
tagName = ''
}

const rootPathIsDefault = !(options && options.rootPath)

if (typeof componentPath === 'string') {
options = Object.assign({
compiler: 'official', // official - 官方编译器、simulate - 纯 js 实现的模拟编译器
Expand All @@ -161,6 +211,7 @@ function load(componentPath, tagName, options = {}) {
wxss: [],
options,
needRunJsList: [],
rootPathIsDefault: typeof componentPath === 'string' && rootPathIsDefault,
}
const hasRegisterCache = {}
const id = register(componentPath, tagName, cache, hasRegisterCache)
Expand Down
8 changes: 8 additions & 0 deletions test/comp12/components/main-status/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Component({
properties: {
msg: {
type: String,
value: '',
},
},
})
6 changes: 6 additions & 0 deletions test/comp12/components/main-status/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"u-icon": "/components/u-icon/index"
}
}
4 changes: 4 additions & 0 deletions test/comp12/components/main-status/index.wxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<view class="main--status">
<u-icon name="star"></u-icon>
<view class="main--msg">{{msg}}</view>
</view>
4 changes: 4 additions & 0 deletions test/comp12/components/main-status/index.wxss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.main--status {
color: #1e6bb8;
font-size: 16px;
}
8 changes: 8 additions & 0 deletions test/comp12/components/u-icon/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Component({
properties: {
name: {
type: String,
value: 'icon',
},
},
})
3 changes: 3 additions & 0 deletions test/comp12/components/u-icon/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"component": true
}
1 change: 1 addition & 0 deletions test/comp12/components/u-icon/index.wxml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<view class="u-icon">[{{name}}]</view>
4 changes: 4 additions & 0 deletions test/comp12/components/u-icon/index.wxss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.u-icon {
color: #e64340;
font-weight: bold;
}
35 changes: 35 additions & 0 deletions test/comp12/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const path = require('path')
const simulate = require('../../index')

function runTest(id) {
const comp = simulate.render(id)

const parent = document.createElement('parent-wrapper')
comp.attach(parent)

// 嵌套的自定义组件需要渲染出自身模板,而不是停留在空节点
expect(simulate.match(comp.dom, `
<wx-view class="page--page">
<main-status>
<wx-view class="main-status--main--status">
<u-icon>
<wx-view class="u-icon--u-icon">[star]</wx-view>
</u-icon>
<wx-view class="main-status--main--msg">这是测试文案</wx-view>
</wx-view>
</main-status>
</wx-view>
`)).toBe(true)
expect(comp.dom.querySelector('main-status').innerHTML).toBeTruthy()
expect(comp.dom.querySelector('u-icon').innerHTML).toBeTruthy()
}

test('comp12', () => {
let id = simulate.load(path.resolve(__dirname, './page/index'), 'page')
runTest(id)

jest.resetModules() // https://github.com/facebook/jest/issues/5120

id = simulate.load(path.resolve(__dirname, './page/index'), 'page', {compiler: 'simulate'})
runTest(id)
})
5 changes: 5 additions & 0 deletions test/comp12/page/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Component({
data: {
msg: '这是测试文案',
},
})
6 changes: 6 additions & 0 deletions test/comp12/page/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"main-status": "/components/main-status/index"
}
}
3 changes: 3 additions & 0 deletions test/comp12/page/index.wxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<view class="page">
<main-status msg="{{msg}}"></main-status>
</view>
3 changes: 3 additions & 0 deletions test/comp12/page/index.wxss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.page {
padding: 10px;
}