0

I am updating my project from Vue 2/Nuxt 2 to Vue 3/Nuxt 3. As i've been doing this my tests have broken and i'm trying to resolve them but every way I try to shallowMount my component returns an empty object or undefined.

The component:

<template>
  <footer data-test="form">
    <div class="footer-top">
      <div class="email-text-container">
        <h2 id="heading__mailing-list-form" class="email-title">{{ email.title }}</h2>
        <h3 class="email-subtext">
          {{ email.subtext }}
        </h3>
      </div>

      <FooterForm />
    </div>
  </footer>
</template>

<script setup>
import { ref, computed } from "vue";
import { fetchEntriesByContentType } from "../composables/contentful-service";
import FooterForm from "./form/FooterForm.vue";

const props = defineProps({
  siteName: String
})

const footer = ref({})

try {
  const data = await fetchEntriesByContentType({
    contentType: "footer",
    title: "Global Footer"
  }) 
  if (!data || data.length < 1) {
      throw `error fetching footer data`;
    } else {
      footer.value = data[0].fields
    }
} catch (error) {
  if (process.env.ROLLBAR_ENABLED === true) {
    Vue.rollbar.error(error);
  }
  throw new Error(error);
}

const email = computed(() => {
  return {
      title: footer?.value.emailTitle,
      subtext: footer?.value.emailSubtext,
    }
})
</script>

The previous test (Vue 2/Nuxt 2):

import { shallowMount } from "@vue/test-utils";
import GlobalFooter from "./GlobalFooter";
import FooterForm from "./form/FooterForm";
import "@testing-library/jest-dom";
import { mockFooterData } from '../assets/data/footer-mock-data';

const mockedFooterData = {
  emailTitle: "email title",
  emailSubtext: "email subtext",
};

describe("GlobalFooter", () => {
  it("Should render EloquaForm component", () => {
    const wrapper = shallowMount(GlobalFooter, {
      propsData: {
        siteName: '/test/',
      }
    });
    expect(wrapper.findComponent(FooterForm).exists()).toBe(true);
  });
});

If I run this test with the updated component written in Vue 3/Nuxt 3 then I get the error: [Vue warn]: Component <Anonymous>: setup function returned a promise, but no <Suspense> boundary was found in the parent component tree. A component with async setup() must be nested in a <Suspense> in order to be rendered.

I read up online about testing async components with the new Vue composition API and I have been trying some different methods, this seems to be the most common suggestion but it doesn't find the child FooterForm component and everything seems to be empty

The new test (Vue 3/Nuxt 3):

import { shallowMount, flushPromises } from "@vue/test-utils";
import { defineComponent } from 'vue';
import GlobalFooter from "./GlobalFooter";
import FooterForm from "./form/FooterForm";
import "@testing-library/jest-dom";
import { mockFooterData } from '../assets/data/footer-mock-data';

const mockedFooterData = {
  propsData: {
  emailTitle: "email title",
  emailSubtext: "email subtext"
  }
};

async function mountWithSuspense (component, options) {
  const wrapper = defineComponent({
      components: { component },
      props: Object.keys(options.props ?? {}),
      template: `<suspense><GlobalFooter v-bind="$props" /></suspense>`
  })

  const result = shallowMount(wrapper, options)

  await flushPromises()
  
  return result
}


test('Should render EloquaForm component', async () => {
  const wrapper = await mountWithSuspense(GlobalFooter, mockedFooterData)

  expect(wrapper.findComponent(FooterForm).exists()).toBe(true);
})

1 Answer 1

0

components: { component } results in a component registered under "component" name, which interferes with built-in component element, while GlobalFooter is unknown.

It should be:

components: { Comp: component },
template: `<suspense><Comp v-bind="$props" /></suspense>`

Or render function can be used instead of a template to refer a component directly instead of resolving it by name:

const result = shallowMount(
  h(Suspense, [
    h(component, options.props)
  ]),
  options
)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.