Teresa Siegmantel
Teresa Siegmantel

Reputation: 903

Vue Infinite Loop During Testing

The following component ends up in an infinite re render loop during testing and I can't figure out why. It works just fine in the application and all it does is receive some data through an event bus, map it to something that can be used in a component tags 'is' property and push that into an array.

<template>
  <div id="notification-area">
    <div v-for="(component, index) in notificationComponents" :key="index">
      <component
          :is="component.options"
          :notification="component.notification"
      />
    </div>
  </div>
</template>

<script lang="ts">
import {Component, Inject, Vue} from "vue-property-decorator";
import {Notification, UserErrorNotification, InfoNotification} from "@/Notification";
import InfoNotificationView from "@/components/notifications/InfoNotificationView.vue";
import UserErrorNotificationView from "@/components/notifications/UserErrorNotificationView.vue";
import {ComponentOptions, DefaultComputed, DefaultData, DefaultMethods, PropsDefinition} from "vue/types/options";

type VueOptions = ComponentOptions<
    Vue,
    DefaultData<Vue>,
    DefaultMethods<Vue>,
    DefaultComputed,
    PropsDefinition<Record<string, {}>>
  >

interface NotificationComponent {
  options: VueOptions;
  notification: Notification;
}

@Component({})
export default class NotificationArea extends Vue {
  @Inject('eventBus') private eventBus!: Vue;
  private notificationComponents = [] as Array<NotificationComponent>;

  private static asNotificationComponent(notification: UserErrorNotification | InfoNotification): NotificationComponent{
    if (notification instanceof UserErrorNotification) {
      return {options: new UserErrorNotificationView().$options, notification: notification}
    }
    return {options: new InfoNotificationView().$options, notification: notification}

  }

  created() {
    this.eventBus.$on('notification', (notification: UserErrorNotification | InfoNotification) => {
      this.notificationComponents.push(NotificationArea.asNotificationComponent(notification));
    })
  }
}
</script>

InfoNotificationView and UserErrorNotificationView are simple wrappers around a BAlert.

The following is the test that results in an out of memory exception.

describe("NotificationArea.vue", () => {
    let wrapper: Wrapper<NotificationArea>;

    beforeEach(() => {
        wrapper = shallowMount(NotificationArea, {
            provide: {
                eventBus: new MockEventBus()
            },
            created() {}
        });
    });

    it("renders the notifications correctly", async () => {
        wrapper.setData({
            notificationComponents: [successNotificationComponent, warningNotificationComponent]
        });
        await wrapper.vm.$nextTick() // <-- Here it hangs.
        const infoNotification = wrapper.find("infonotificationview-stub");
        expect(infoNotification.props('notification')).toBe(successNotificationComponent);
        const userErrorNotification = wrapper.find("usererrornotificationview-stub")
        expect(userErrorNotification.props("notification")).toBe(warningNotificationComponent);
    });
});
 

Upvotes: 2

Views: 430

Answers (1)

Teresa Siegmantel
Teresa Siegmantel

Reputation: 903

As it turns out, the problem was jest printing a very big object, since successNotificationComponent contains a vue component.

I fixed it by putting a testId into the notification during testing and checking for that.

Upvotes: 1

Related Questions