Skip to content

enableAutoDestroy stops working when a component render fails #1963

Open
@Kapcash

Description

@Kapcash

Subject of the issue

When enabling the utility enableAutoDestroy, everything works as expected until a test mounts a component that fails to render (an error occurs in the template for instance).

When it happens, the tests stops, and the afterEach hook is calls, triggering the auto wrapper destroy from the utility.
But wrapper.destroy() throws an exception because the component has failed to render (not sure why though).

So the wrapper isn't destroyed and is kept in the list of tracked wrappers to destroy.
Then, every tests after this crash will fail because the list of wrappers has not been emptied!

Maybe it will be clearer with a code sample:

// vue-test-utils/packages/test-utils/src/auto-destroy.js

  hook(function () {
    wrapperInstances.forEach(function (wrapper) {
      if (wrapper.vm || wrapper.isFunctionalComponent) {
       // **throws an exception (error in render template) that is not catch**
        wrapper.destroy();
      }
    });
    // **will never be executed because of the exception**
    wrapperInstances.length = 0;
  });

So on the next test - that is supposed to pass - wrapperInstances still has the previous wrapper that should have been destroyed:

wrapperInstances === [{ /* wrapper failing to destroy */ }, { /* next wrapper that could be destroyed */}]

So on after hook run, it will try again to destroy the blocked wrapper, and fail again and the following wrappers are never destroyed

Steps to reproduce

Configure the auto destroy on the afterEach hook in the global jest setup.

// jest.setup.js

enableAutoDestroy(afterEach)

Then, create a test suite with:

  • the first test fails to render a component's template
  • the second test works

Run the tests, and both will fail even though they pass when run individually.

Expected behaviour

Only the first test may fail.

Actual behaviour

All the tests after the failing one are impacted and fail.

Possible Solution

The solution would be to add a try / catch around the wrapper.destroy() in the utility, so that even if one destroy fails, it still flush the tracked wrapper array, and we don't end up with a growing list of wrappers to destroy, that will never be destroyed.

// vue-test-utils/packages/test-utils/src/auto-destroy.js

  hook(function () {
    wrapperInstances.forEach(function (wrapper) {
      if (wrapper.vm || wrapper.isFunctionalComponent) {
        try {
           wrapper.destroy();
        } catch (err) {
            // **Print a warning? Remove the wrapper from the list?**
        }
      }
    });
    // **will be executed even if a destroy has failed**
    wrapperInstances.length = 0;
  });

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions