Popover doesn't close in test #666
Replies: 5 comments
-
| Did u find solution? | 
Beta Was this translation helpful? Give feedback.
-
| @voskresla No, unfortunately not yet :/ For now, I removed the failing test (which isn't nice of course). But I would very much like to know what's causing the failure. If you come across a solution yourself, please let me know :) | 
Beta Was this translation helpful? Give feedback.
-
| Did you register the close-popover directive? | 
Beta Was this translation helpful? Give feedback.
-
| Hi, I further simplified the component for showing, but the "main" component reflects this behavior. In contrast to the component's code, which I posted earlier, I outsourced the content of the popover to a new component  <template>
	<v-popover>
		<div>Trigger</div>
		<template slot="popover">
			<slot></slot>
		</template>
	</v-popover>
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import Vue from 'vue';
import VTooltipDefault, { VPopover } from 'v-tooltip';
Vue.component('v-popover', VPopover);
Vue.use(VTooltipDefault, { disposeTimeout: 200 }); // needed for transitions, test always fails if it's missing
export default defineComponent({
	setup(){},
})
</script>And  <template>
	<div v-close-popover @click="clickHandler"><slot></slot></div>
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import Vue from 'vue';
import { VClosePopover } from 'v-tooltip';
Vue.directive('close-popover', VClosePopover);
/**
 * Simple component to be used as option e.g. for MySelect component.
 */
export default defineComponent({
	setup(props, { emit }) {
		function clickHandler(event: Event): void {
			emit('click', event);
		}
		return { clickHandler };
	},
});
</script>Corresponding test: import { render, fireEvent, waitFor, waitForElementToBeRemoved } from '@testing-library/vue';
import '@testing-library/jest-dom';
import MySelect from './mySelect.vue';
import MyOption from './myOption.vue';
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);
// patch for error in v-tooltip package:
// [Vue warn]: Error in directive tooltip bind hook: "TypeError: document.createRange is not a function"
// see https://stackoverflow.com/questions/61691375/jest-test-typeerror-document-createrange-is-not-a-function
document.createRange = () => ({
	// eslint-disable-next-line @typescript-eslint/no-empty-function
	setStart: () => {},
	// eslint-disable-next-line @typescript-eslint/no-empty-function
	setEnd: () => {},
	// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
	//@ts-ignore
	commonAncestorContainer: {
		nodeName: 'BODY',
		ownerDocument: document,
	},
});
describe('My select component', () => {
        // ... some other tests
	it('closes the popover once the popover content is clicked', async () => {
		const { getByText, queryByText } = render(MySelect, {
			stubs: {
				'my-option': MyOption,
			},
			slots: {
				default: `
				<my-option value="1" v-close-popover>Option 1</my-option>
				<my-option value="2" v-close-popover>Option 2</my-option>`,
			},
		});
		await waitFor(() => {
			expect(getByText('Trigger')).toBeInTheDocument();
		});
		const trigger = getByText('Trigger');
		await fireEvent.click(trigger);
		await waitFor(() => {
			expect(getByText('Option 1')).toBeInTheDocument();
		});
		const content = getByText('Option 1');
		await fireEvent.click(content);
		await waitForElementToBeRemoved(() => queryByText('Option 1')); // --> This fails
	});
});I ran the test sequentially multiple times and counted: It failed in 4 of 25 cases, always for the same reason ( nteuffel vue-components % npm run test src/components/mySelect
> @my-project/[email protected] test /Users/nteuffel/[…]/vue-components
> vue-cli-service test:unit "src/components/mySelect"
 FAIL  src/components/mySelect/mySelect.spec.ts
  My select component
    ✕ closes the popover once the popover content is clicked (1131ms)
  ● My select component › closes the popover once the popover content is clicked
    Timed out in waitForElementToBeRemoved.
    <html>
      <head>
        <style
          type="text/css"
        >
          .resize-observer[data-v-b329ee4c]{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%;border:none;background-color:transparent;pointer-events:none;display:block;overflow:hidden;opacity:0}.resize-observer[data-v-b329ee4c] object{display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1}
        </style>
      </head>
      <body>
        <div>
          <div
            class="v-popover open"
          >
            <div
              aria-describedby="popover_5dvdjzarno"
              class="trigger"
              style="display: inline-block;"
            >
              <div>
                Trigger
              </div>
               
            </div>
             
          </div>
        </div>
        <div
          aria-hidden="false"
          class="tooltip popover vue-popover-theme open"
          id="popover_5dvdjzarno"
          style="visibility: visible; position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(NaNpx, NaNpx, 0);"
          tabindex="0"
          x-placement="bottom"
        >
          <div
            class="wrapper"
          >
            <div
              class="tooltip-inner popover-inner"
              style="position: relative;"
            >
              <div>
                <div
                  value="1"
                >
                  Option 1
                </div>
                 
                <div
                  value="2"
                >
                  Option 2
                </div>
              </div>
               
              <div
                class="resize-observer"
                data-v-b329ee4c=""
                tabindex="-1"
              >
                <object
                  aria-hidden="true"
                  data="about:blank"
                  tabindex="-1"
                  type="text/html"
                />
              </div>
            </div>
             
            <div
              class="tooltip-arrow popover-arrow"
            />
          </div>
        </div>
      </body>
    </html>
      45 |              const content = getByText('Option 1');
      46 |              await fireEvent.click(content);
    > 47 |              await waitForElementToBeRemoved(() => queryByText('Option 1')); // --> This fails
         |                    ^
      48 |      });
      49 | });
      at waitForElementToBeRemoved (../../node_modules/@testing-library/dom/dist/wait-for-element-to-be-removed.js:22:24)
      at src/components/mySelect/mySelect.spec.ts:47:9
      at step (../../node_modules/tslib/tslib.js:136:27)
      at Object.next (../../node_modules/tslib/tslib.js:117:57)
      at fulfilled (../../node_modules/tslib/tslib.js:107:62)
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.798s
Ran all test suites matching /src\/components\/mySelect/i.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @my-project/[email protected] test: `vue-cli-service test:unit "src/components/mySelect"`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the @my-project/[email protected] test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/nteuffel/.npm/_logs/2021-01-11T10_33_41_515Z-debug.log
nteuffel vue-components % npm run test src/components/mySelect
> @my-project/[email protected] test /Users/nteuffel/[…]/vue-components
> vue-cli-service test:unit "src/components/mySelect"
 PASS  src/components/mySelect/mySelect.spec.ts
  My select component
    ✓ closes the popover once the popover content is clicked (376ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.656s, estimated 3s
Ran all test suites matching /src\/components\/mySelect/i.I have absolutely no clue why some of the tests fail and others don't. 4/25 seems a good rate, still I can't risk integrating this test into my test suite unless it passes always. Thanks in advance. | 
Beta Was this translation helpful? Give feedback.
-
| Hi, 
 I set up a minimal component to show this behavior: <template>
  <div>
    <v-popover ref="myComponentRef">
      <div>Trigger</div>
      <template slot="popover">
        <div @click="handleClose">
          Content
        </div>
      </template>
    </v-popover>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref } from '@vue/composition-api';
import Vue from 'vue';
import { VPopover } from 'v-tooltip';
Vue.component('v-popover', VPopover);
export default defineComponent({
  setup() {
    const myComponentRef = ref();
    function handleClose() {
      myComponentRef.value.hide();
    }
    return {
      handleClose,
      myComponentRef,
    };
  },
});
</script>When I open the component in Storybook, everything works as intended: The popover opens when I click on  myComponent.spec.ts: import { render, fireEvent, waitFor } from '@testing-library/vue';
import '@testing-library/jest-dom';
import MyComponent from './myComponent.vue';
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);
// patch for error in v-tooltip package:
// [Vue warn]: Error in directive tooltip bind hook: "TypeError: document.createRange is not a function"
// see https://stackoverflow.com/questions/61691375/jest-test-typeerror-document-createrange-is-not-a-function
document.createRange = () => ({
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  setStart: () => {},
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  setEnd: () => {},
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
  //@ts-ignore
  commonAncestorContainer: {
    nodeName: 'BODY',
    ownerDocument: document,
  },
});
describe('MyComponent', () => {
  // Works
  it('renders the trigger', () => {
    const { getByText } = render(MyComponent);
    // renders trigger
    expect(getByText('Trigger')).toBeInTheDocument();
  });
  // Works
  it('opens the tooltip', async () => {
    const { getByText } = render(MyComponent);
    const trigger = getByText('Trigger');
    fireEvent.click(trigger);
    await waitFor(() => {
      expect(getByText('Content')).toBeInTheDocument();
    });
  });
  // Fails
  it('closes the tooltip on window click', async () => {
    const { getByText } = render(MyComponent);
    const trigger = getByText('Trigger');
    fireEvent.click(trigger);
    await waitFor(() => {
      expect(getByText('Content')).toBeInTheDocument();
    });
    fireEvent.click(window); // throws error
    await waitFor(() => {
      // this fails
      expect(getByText('Content')).not.toBeInTheDocument();
    });
  });
  // Fails
  it('closes the tooltip on content click', async () => {
    const { getByText } = render(MyComponent);
    const trigger = getByText('Trigger');
    fireEvent.click(trigger);
    await waitFor(() => {
      expect(getByText('Content')).toBeInTheDocument();
    });
    fireEvent.click(getByText('Content'));
    await waitFor(() => {
      // this fails
      expect(getByText('Content')).not.toBeInTheDocument();
    });
  });
});When I test for closing the tooltip on window click (third test), an error is thrown: Am I invoking the tests wrongly? If so: What should I do differently? Or do I have to add some special handling for the window click in my tests? By the way: This is a pretty awesome and useful package, apart from these minor issues :) Thanks for your efforts! | 
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
first of all: Thanks for creating such a great library! For now, everything works fine for me, except for one small issue:
I created an own
selectcomponent, very similar to the native one: I can select a value from a list of options, displayed in a dropdown. When clicking on an option, that option is displayed as value and the dropdown closes (handled by the v-close-popover directive). When using the component e.g. in Storybook, everything works fine. But when I want to test its functionalities in a spec file, the dropdown doesn't close when selecting an option.I would be very thankful for any hint as to what I'm doing wrong or where I should look for a solution.
Cheers!
Nanda
Here's my component code:
And this is the test file, where all tests work, except for the last one:
Beta Was this translation helpful? Give feedback.
All reactions