vue-a11y / vue-announcer

A simple way with Vue to announce any useful information for screen readers.
MIT License
230 stars 9 forks source link

TypeError: Cannot destructure property 'data' of 'e' as it is undefined #40

Open felixzapata opened 1 year ago

felixzapata commented 1 year ago

Hi, just using vue-announcer (v3.1.5) in a component like:

const { assertive } = useAnnouncer(); (or polite etc) throws an error during the component test:

Captura de pantalla 2022-09-16 a las 9 26 51

Captura de pantalla 2022-09-16 a las 9 56 43

If you only import the vue-announcer there will be no error.

The component is under a Vue 3 application using TypeScript, Composition API, and SFC (with <script setup>). The tests are with Vitest, also written in Typescript.

The skeleton of my component test is:

import { describe, it, expect } from "vitest";
import i18n from "../../i18n";
import { mount } from "@vue/test-utils";
import MyComponent from "./MyComponent.vue";
import type { User } from "./User";

it("emit profile-saved", async () => {
    const wrapper = mount(Mycomponent, {
      global: { plugins: [i18n] },
      props: { user: { ...user } },
    } as any);
felixzapata commented 1 year ago

This is the same error, running a very simple test added to your demo folder inside the next branch:

Captura de pantalla 2022-09-16 a las 11 11 31

The component:

<script setup lang="ts">

  import { useAnnouncer } from '../../../src'

  const { assertive } = useAnnouncer();

  </script>

  <template>
    <h1>hi</h1>

  </template>

The test:

import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import MyComponent from "./MyComponent.vue";
describe("MyComponent", () => {
  it("very simple test", async () => {
    const wrapper = mount(MyComponent as any);
    expect(1).toEqual(1);
  });
});

Maybe the solution to this error is creating a mock for the vue-announcer inside the component that is going to use it. Something like:

vi.mock("@vue-a11y/announcer", () => {
  const useAnnouncer = () => {
    return {
      assertive: vi.fn()
    }
  };
  return { useAnnouncer };
});

At least in the test inside the demo it works as:

vi.mock('../../../src', () => {
  const useAnnouncer = () => {
    return {
      assertive: vi.fn()
    }
  };
  return { useAnnouncer }
})
felixzapata commented 1 year ago

The only way I can run the test mocking the package name is using something like:

vi.mock('@vue-a11y/announcer/dist/announcer.es.js', () => {
  const useAnnouncer = () => {
    return {
      assertive: vi.fn()
    }
  };
  return { useAnnouncer }
})

because @vue-a11y/announcer is totally ignored by vi.mock, maybe related to this issue.

daniilgri commented 11 months ago

@felixzapata is it possible somehow to test methods from useAnnouncer composable with this approach of mocking?

felixzapata commented 11 months ago

vi.mock('@vue-a11y/announcer/dist/announcer.es.js'

Maybe, It was not necessary for me but in other approaches, I did something similar.

In the same test file:

import { useAnnouncer } from '@vue-a11y/announcer';
vi.mock('@vue-a11y/announcer/dist/announcer.es.js', () => {
  const useAnnouncer = () => {
    return {
      assertive: vi.fn()
    }
  };
  return { useAnnouncer }
})

Inside the suite:

vi.mocked(useAnnouncer, { partial: true }).mockReturnValue({
      polite: () => { return true; },
    });