Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emitted events doesn't work with defineModel #572

Open
ExEr7um opened this issue May 31, 2023 · 6 comments · May be fixed by #1011
Open

Emitted events doesn't work with defineModel #572

ExEr7um opened this issue May 31, 2023 · 6 comments · May be fixed by #1011
Labels

Comments

@ExEr7um
Copy link
Contributor

ExEr7um commented May 31, 2023

In v0.8.1 emitted events were fixed in mountSuspended, but they still doesn't work with defineModel.

Added some tests for it in danielroe/nuxt-vitest#193.

@ExEr7um
Copy link
Contributor Author

ExEr7um commented May 31, 2023

@danielroe also added some tests for it in danielroe/nuxt-vitest#193. I included test with mount that passes and test with mountSuspended that fails.

@danielroe danielroe added bug Something isn't working good first issue Good for newcomers good reproduction ✨ labels Jun 2, 2023
@danielroe danielroe transferred this issue from danielroe/nuxt-vitest Dec 2, 2023
@danielroe
Copy link
Member

I've merged the tests in (as a TODO) in #629.

@wattanx
Copy link
Collaborator

wattanx commented Feb 10, 2024

I will write down what I have found in my research in case it helps anyone.

Even with defineModel, it works as expected for update:modelValue.

<button
  id="changeModelValue"
  @click="$emit('update:modelValue', true)"
 />

If modelValue = true, the event exists in the emitted of MountSuspendedComponent.
You can confirm this by modifying the test as follows

// FIXME: fix this failing test
it('can receive emitted events from components mounted within nuxt suspense using defineModel', async () => {
  const component = await mountSuspended(WrapperTests)
  component.find('button#changeModelValue').trigger('click')
  // outouts: { 'update:modelValue': [ [ true ] ] }
  console.log(component.findComponent({ name: 'MountSuspendedComponent' }).emitted())
  expect(component.emitted()).toHaveProperty('update:modelValue')
})

@bborlet
Copy link

bborlet commented Jun 19, 2024

HI,

This does not work for me :
The test is done on the dumbest component with v-model :

<script setup lang="ts">
const innerValue = defineModel({ type: String });
</script>
<template>
	<input v-model="innerValue" />
</template>
	it("emits input event", async () => {
		const wrapper = await mountSuspended(VMT, {
			props: {
				modelValue: "initialText",
				"onUpdate:modelValue": (e) =>
					wrapper.setProps({ modelValue: e }),
			},
		});
		const input = wrapper.find("input");
		await input.setValue("newvalue");
		expect(wrapper.emitted("update:modelValue")).toBeTruthy(); 
	});

Everything comes straight from the doc, but

  • wrapper is typed as any because it self reference itself in the onUpdate
  • wrapper.emitted("update:modelValue") is undefined

The same test but with vue/testutils used directly succeed, even though wrapper is still typed as any:

it("emits input event", async () => {
		const wrapper = mount(VMT, {
			props: {
				modelValue: "initialText",
				"onUpdate:modelValue": (e) =>
					wrapper.setProps({ modelValue: e }),
			},
		});
		const input = wrapper.find("input");
		await input.setValue("newvalue");
		expect(wrapper.emitted("update:modelValue")).toBeTruthy();
	});

What is the recommended way to test this ? Maybe I should just not test that, it's practically like testing vue in this case right ?

@sumomo015
Copy link

I found that when testing with the following code, a warning like this appears in the terminal.
Hope it helps.

it('入力値がtrimされることを確認する', async () => {
  const wrapper = await mountSuspended(PartsInputText, {
    props: {
      'modelValue': '',
      'name': 'test-input',
      'onUpdate:modelValue': (e: string) => wrapper.setProps({ modelValue: e }),
    },
  })
  await wrapper.find('input').setValue('  テスト  ')
  expect(wrapper.emitted('update:modelValue')).toBeTruthy()
  expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['テスト'])
  expect(wrapper.props('modelValue')).toBe('テスト')
})
[Vue warn]: Property "onUpdate:modelValue" was accessed during render but is not defined on instance. 
  at <MountSuspendedComponent modelValue="" name="test-input" onUpdate:modelValue=fn<onUpdate:modelValue> > 
  at <MountSuspendedHelper> 
  at <Anonymous ref="VTU_COMPONENT" > 
  at <VTUROOT>
[Vue warn]: Property "onUpdate:modelValue" was accessed during render but is not defined on instance. 
  at <MountSuspendedComponent modelValue="テスト" name="test-input" onUpdate:modelValue=fn<onUpdate:modelValue> > 
  at <MountSuspendedHelper> 
  at <Anonymous ref="VTU_COMPONENT" > 
  at <VTUROOT>

@stafyniaksacha
Copy link

stafyniaksacha commented Nov 3, 2024

This error also occurs without defineModel neither with option api:

<script setup lang="ts">
// const [modelValue] = defineModel<string>();

const props = defineProps<{
  modelValue: string;
}>();
const emits = defineEmits<{
  'update:modelValue': [value: string];
}>();

const modelValue = computed({
  get() {
    return props.modelValue;
  },
  set(value) {
    emits('update:modelValue', value);
  },
});
</script>
import { mountSuspended } from '@nuxt/test-utils/runtime';
import { mount } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';
import MyComp from './MyComp.vue';

describe('MyComp', () => {
  it('should have v-model events working with mountSuspended', async () => {
    const comp = await mountSuspended(MyComp, {
      props: {
        modelValue: 'hello',
        'onUpdate:modelValue': (e: any) => comp.setProps({ modelValue: e }),
      },
    });

    await comp.get('input').setValue('test');
    // this one fails
    expect(comp.props('modelValue')).toBe('test');
  });

  it('should have v-model events working with mount', async () => {
    const comp = await mount(MyComp, {
      props: {
        modelValue: 'hello',
        'onUpdate:modelValue': (e: any) => comp.setProps({ modelValue: e }),
      },
    });

    await comp.get('input').setValue('test');
    expect(comp.props('modelValue')).toBe('test');
  });
});

repro: https://stackblitz.com/edit/nuxt-starter-ategmh?file=components%2FMyComp.vue,components%2FMyComp.spec.ts

@wattanx wattanx linked a pull request Nov 9, 2024 that will close this issue
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants