Cypress 中 Vue3 应用程序的视口更改给出 TypeError ref.value 为 null

Wil*_*urb 1 javascript cypress vuejs3

在 Cypress 中,我在执行任何其他测试后更改了 Veu3 应用程序的视口,它给出了错误:“(未捕获的执行)TypeError a.value is null”。

产生错误的最小应用程序:

<script setup>
  import { ref, onMounted } from 'vue'
  const a = ref(null)
  
  onMounted (() => {
    function onWindowResize() {
      window.addEventListener("resize", () => {
        //a.value always needs to refresh when the window resizes to different content
        a.value.textContent = 'Text displayed here will be decided on the window size'
      })
    }
    onWindowResize()
  })
</script>

<template>
<div>
  <span ref="a" data-testid="test1">M</span>
  <a> ..more</a>
</div>
</template>
Run Code Online (Sandbox Code Playgroud)

通过以下测试。这里需要注意的有趣的事情是,如果您不包含第一个测试,则不会出现错误。

import Test from '../Test.vue'

describe('run 2 test', () => {
  it('The error only appears if I run a test before I run the viewport change', () => {
    cy.mount(Test)
    cy.get('[data-testid="test1"]').get('a').should('contain', ' ..more')
  })

  it('The error originates on the first viewport changes it appears', () => {
    cy.mount(Test)
//so it appears here
    cy.viewport(550, 750)

    let charCount = 0
    cy.get('[data-testid="test1"]').then(($span) => {
      charCount = String($span.text()).length;
    })
    cy.viewport(400, 400)
    cy.get('[data-testid="test1"]').then(($span) => {
      const newCharCount = String($span.text()).length;
      expect(newCharCount).to.be.eq(charCount)
    })
  })
})
Run Code Online (Sandbox Code Playgroud)

我找到了这个问题的答案:“Vue3 TypeError ref.value is null”并尝试添加defineExpose()但它不会改变任何事情。我尝试重新声明const a = ref(null)内部onMounted()也没有运气。一直在搜索,但找不到解决方案,任何帮助将不胜感激,因为很多测试将围绕视口更改进行。

该错误会导致应用程序的其余部分(取决于 a.value)失败。

更新 显然是我看不出问题所在。所以,我想了解为什么 a.value 不应该存在于 unMounted() 中(即使这是de Vue 文档中的示例)。也是为什么它在浏览器中工作而没有任何错误。为什么它在 Cypress 中工作是在测试之前没有测试?

我真的很想了解并找到解决这个问题的方法。

Ala*_*paz 8

当我在 React 中使用 ref 时,在访问/分配它之前检查它总是一个好习惯ref.value

因此,如果我在调整大小侦听器中放置一个防护,则会出现错误

(未捕获的异常)类型错误:无法设置 null 的属性(设置“textContent”)

消失了。

<script setup>
  import { ref, onMounted } from 'vue'
  const a = ref(null)
  
  onMounted (() => {
    function onWindowResize() {
      window.addEventListener("resize", () => {

        // check that the ref is linked to the element before using it
        if (a.value) {
          a.value.textContent = 'resize'
        }
      })
    }
    onWindowResize()
  })
</script>
Run Code Online (Sandbox Code Playgroud)

但不确定测试的逻辑是否仍然成立,因为它可能会丢弃调整大小事件。

因此,我添加了对文本“resize”(由侦听器设置)的检查,并且它通过了。

其余的测试没有通过,因为现在缩放器正在运行。

it('The error originates on the first viewport changes it appears', () => {
  cy.mount(Test)

  cy.viewport(550, 750)

  let charCount = 0
  cy.get('[data-testid="test1"]').then(($span) => {

    charCount = $span.text().length; 

    cy.viewport(400, 400)

    cy.get('[data-testid="test1"]')
      .should('have.text', 'resize')               // passes
      .then(($span) => {
        const newCharCount = $span.text().length;
        expect(newCharCount).to.be.eq(charCount)   // now failing because resize occurred
      })
  })
})
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

此外,开发控制台中会发出警告,表明该resize事件已被弃用并将被删除(chrome 浏览器)。

它表明

考虑使用 MutationObserver 代替。


Bil*_*urr 6

我认为你的测试是错误的,如果调整大小改变了文本,那么expect(newCharCount).to.be.eq(charCount)就不会通过,因为现在字符数更大了。看a.value.textContent = ...

\n

你在那里打错字了吗?

\n
    let charCount = 0\n    cy.get(\'[data-testid="test1"]\').then(($span) => {\n      charCount = String($span.text()).length;\n    })\n    cy.viewport(400, 400)\n    cy.get(\'[data-testid="test1"]\').then(($span) => {\n      const newCharCount = String($span.text()).length;\n      expect(newCharCount).to.be.gt(charCount)     <-- size has increased \n    })\n
Run Code Online (Sandbox Code Playgroud)\n
\n

添加守卫是阻止 的正确操作uncaught:exception

\n

窗口调整大小独立于 Vue 应用程序,卸载组件后发生错误。

\n

添加一些调试:

\n
<script setup>\n  import { ref, onMounted, onUnmounted } from \'vue\'\n\n  const el = ref(null)\n  \n  let isMounted = false\n\n  onMounted (() => {\n    isMounted = true\n    console.log(\'Mounted: ref el\', el.value, isMounted)\n    window.addEventListener("resize", () => {\n      if (isMounted) {\n        el.value.textContent = \'some new text\'\n      }\n    })\n  })\n\n  onUnmounted (() => {\n    isMounted = false\n    console.log(\'Unmounted: ref el\', el.value, isMounted)\n  })\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n

安慰:

\n
    \n
  • 已安装:ref el <span data-testid=\xe2\x80\x8b"test1">\xe2\x80\x8bM\xe2\x80\x8b\xe2\x80\x8b true
  • \n
  • 已卸载:ref el null false
  • \n
  • 已安装:ref el <span data-testid=\xe2\x80\x8b"test1">\xe2\x80\x8bsome new text\xe2\x80\x8b\xe2\x80\x8b true
  • \n
\n

显示el安装时 ref 指向跨度(如预期)。

\n

从技术上讲,onBeforeUnmount()您应该删除侦听器,这也将摆脱uncaught:exception.

\n

由于调整大小监听器已被弃用,请将其更改为 MutationObserver。

\n

或者,使用@vueuse/core 中的 useElementSize

\n