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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: ability to pass components to HooksConfig #30453

Open
sand4rt opened this issue Apr 21, 2024 · 6 comments 路 May be fixed by #30455
Open

[Feature]: ability to pass components to HooksConfig #30453

sand4rt opened this issue Apr 21, 2024 · 6 comments 路 May be fixed by #30455

Comments

@sand4rt
Copy link
Collaborator

sand4rt commented Apr 21, 2024

馃殌 Feature Request

The ability to pass components to HooksConfig, probably by using the resolveImportRef to resolve the hooksConfig;

Example

beforeMount(async ({ app, hooksConfig }) => {
  for (const [name, component] of Object.entries(hooksConfig?.components || {}))
    app.component(name, component);
});
import { test, expect } from '@playwright/experimental-ct-vue';
import DefaultSlot from '@/components/DefaultSlot.vue';
import Button from '@/components/Button.vue';

test('render a component as slot', async ({ mount }) => {
  const component = await mount(DefaultSlot, {
    slots: {
      default: '<Button title="Submit" />',
    },
    hooksConfig: {
      components: { Button }
    }
  });
  await expect(component).toContainText('Submit');
});

Motivation

It simplifies testing slots and other use cases such as providing plugins

@sand4rt sand4rt linked a pull request Apr 21, 2024 that will close this issue
@pavelfeldman
Copy link
Member

Could you help me understand why we need to register component in beforeMount for this use case to work? I was hoping it would work out of the box.

@sand4rt
Copy link
Collaborator Author

sand4rt commented Apr 22, 2024

Vue is unable to locate the <Button /> component when it's passed to the slot as a string.

So this test will fail because there's no reference from the <Button /> string to the actual component:

-- DefaultSlot.vue <-- NOTE: Button component not registered here
<template>
  <main>
    <slot />
  </main>
</template>
test('render a component as slot', async ({ mount }) => {
  const component = await mount(DefaultSlot, {
    slots: {
      default: '<Button title="Submit" />', <-- NOTE: There is no reference
    },
  });
  await expect(component).toContainText('Submit');
})

Vue test utils follows a similar approach: https://test-utils.vuejs.org/api/#global-components. Their mount.global is kind of similar to Playwright's mount.hooksConfig: https://test-utils.vuejs.org/api/#global

@pavelfeldman
Copy link
Member

Ah, I missed the string quotes around <Button>, it makes sense to me now. In terms of the proposed shape of the API, I see hooksConfig as a user object w/o schema. In this case it seems like Vue would benefit from framework-specific components property that would point to the component registry. Does it make sense?

@sand4rt
Copy link
Collaborator Author

sand4rt commented Apr 23, 2024

I see hooksConfig as a user object w/o schema

I actually use hooksConfig specifically for registering global things like mixins, components, plugins and directives. It's been a while, but hooksConfig was introduced two years ago for this reason right?: #14416

In this case it seems like Vue would benefit from framework-specific components property that would point to the component registry. Does it make sense?

It is a common scenario, but i don't think it needs a specific API as it saves just a few lines of code. This would also be the first API that's different from the rest and i kind of like the flexibility of the hooksConfig.

It's a trade-off between a generic hooksConfig API or framework-specific APIs IMO. I recently sent something about this on Discord. With the Angular adapter we are also confronted with the question: 'domain specific or generic'

@sand4rt
Copy link
Collaborator Author

sand4rt commented Apr 23, 2024

Another option is to put the boilerplate code in playwright-create:

// /playwright/index.ts
beforeMount(async ({ app, hooksConfig }) => {
  for (const [name, component] of Object.entries(hooksConfig?.components || {}))
    app.component(name, component);
});

@pavelfeldman
Copy link
Member

Ah, so you want the user to control both sides of the story, so hooksConfig's schema is left to the user to define? That's fine with me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants