wechat-miniprogram / miniprogram-simulate

小程序自定义组件测试工具集
MIT License
501 stars 66 forks source link

无法通过选择器获取列表渲染的元素的子元素 #75

Closed Ayase-252 closed 3 years ago

Ayase-252 commented 3 years ago

考虑组件

<view class="item" wx:for="{{items}}">
  <view class="child">{{item}}</view>
</view>
Component({
  data: {
    items: [1, 2]
  },
})

执行测试用例(jest)

const path = require('path')
const simulate = require("miniprogram-simulate")

it("should be able to fetch child in comp rendered over a list", () => {
  const comp = simulate.load(path.resolve(__dirname, "../index"),)
  const renderedComp = simulate.render(
    simulate.load({
      usingComponents: {
        comp
      },
      template: `<comp id="root"></comp>`
    })
  )
  const container = document.createElement("wrapper")
  renderedComp.attach(container)

  const root = renderedComp.querySelector("#root")
  const items = root.querySelectorAll(".item")

  expect(items).toHaveLength(2)

  const first = items[0]
  console.log(first.dom.outerHTML)
  const childOfFirst = first.querySelector(".child")

  expect(childOfFirst).toBeTruthy()
})

测试运行结果

 FAIL   unit  pages/user-data-modify/components/wrong/__tests__/index.spec.js
  ● Console

    console.warn
      WXMLRT_$gwx:index.wxml:view:2:2: Now you can provide attr `wx:key` for a `wx:for` to improve performance.

      at _wp (eval at getWxml (node_modules/miniprogram-simulate/src/compile.js:31:41), <anonymous>:15:25)
      at m0 (eval at getWxml (node_modules/miniprogram-simulate/src/compile.js:31:41), <anonymous>:1087:1)
      at eval (eval at getWxml (node_modules/miniprogram-simulate/src/compile.js:31:41), <anonymous>:1105:1)
      at TemplateEngine._generateFunc (node_modules/j-component/src/template/transform.js:99:24)
      at TemplateEngine.createInstance (node_modules/j-component/src/componentmanager.js:195:21)
      at Function.g._advancedCreate (node_modules/miniprogram-exparser/exparser.min.js:3:11795)
      at _.createComponent (node_modules/miniprogram-exparser/exparser.min.js:3:24645)
      at renderExparserNode (node_modules/j-component/src/render/render.js:161:33)

    console.log
      <wx-view class="main--item"><wx-view class="main--child">1</wx-view></wx-view>

      at Object.<anonymous> (pages/user-data-modify/components/wrong/__tests__/index.spec.js:40:11)

  ● should be able to fetch child in comp rendered over a list

    expect(received).toBeTruthy()

    Received: undefined

      41 |   const childOfFirst = first.querySelector(".child")
      42 |
    > 43 |   expect(childOfFirst).toBeTruthy()
         |                        ^
      44 | })

      at Object.<anonymous> (pages/user-data-modify/components/wrong/__tests__/index.spec.js:43:24)

childOfFirst 应该获取列表渲染出来的第一个元素的 .child 元素,上方的 console.log 也确认了 first 元素中含有一个 .child 元素。但是实际上通过 querySelector(".child") 返回 undefined.

JuneAndGreen commented 3 years ago

要理解小程序里 view 也是一个组件,不等同于 div,小程序的组件大体上遵循 web components 的概念设计。.item 和 .child 在一个 shadowTree,所以要用 root.querySelector(".child")

ps:这和小程序的 selectorQuery 是一个机制,组件的 querySelector 一定是选择该组件 shadowTree 下的节点,如果跨 shadowTree 选择,可用 >>> 选择器。

Ayase-252 commented 3 years ago

@JuneAndGreen

谢谢回答,问题解决,closing

PS:elem.querySelector() 在 web 中是可以找到其子树下面的符合选择器的元素的。测试框架这样有点反直觉。BTW,请问如何获取到对应第 n 个列表渲染元素的子元素?