help-me-mom / ng-mocks

Angular testing library for mocking components, directives, pipes, services and facilitating TestBed setup
https://www.npmjs.com/package/ng-mocks
MIT License
1.05k stars 76 forks source link

Use CUSTOM_ELEMENTS_SCHEMA with mockBuilder #1181

Closed Tallyb closed 2 years ago

Tallyb commented 3 years ago

Is there a way to use CUSTOM_ELEMENTS_SCHEMA when using mockBuilder, or do I need to revert to TestBed?

satanTime commented 3 years ago

Hi @Tallyb,

Might you leverage your case a bit?

The idea of ng-mocks is to avoid usage of CUSTOM_ELEMENTS_SCHEMA, and to let tests to rely on exactly the same interfaces in mock declarations as their original ones have.

In theory, you could mix MockBuilder.build and TestBed, but I haven't tried it so far.

beforeEach(() => {
  const ngModule = MockBuilder(null, MyModule).build();

  return TestBed.configureTestingModule({
    ...ngModule,
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
  });
});
Tallyb commented 3 years ago

Do you mean - avoid using [NO_ERRORS_SCHEMA]?

Here is a simplified example of my scenario. I am building a directive (selector: my-directive). We use web components and the directive is accessing a specific web component (my-component). In order to test the directive, I want to have a test component that has the WC. something like:

<my-component> 
   <div my-directive/>
</my-component>

Using mockBuilder alone throws an error that it does not recognize my-component.

Your example looks good, but it will be great to have mockBuilder catering for schemas as well, something like:

mockBuilder(myComponent).schemas('CUSTOM_ELEMENTS_SCHEMA')
satanTime commented 3 years ago

Ah, I see now. So it's only about using dashes in selectors.

Yep, it makes sense and I'll add its support with the next release. However, I'm going on vacation and be back in the second part of October.

satanTime commented 3 years ago

Hi again, I was thinking about it overnight, and didn't get it fully. All selectors are already app-*, so they support dashes without CUSTOM_ELEMENTS_SCHEMA.

Could you share how the directive is accessing the component?

In my understanding, it still should work like:

MockRender(MyDirective);

or

MockRender(`<div my-directive></div>`);
Tallyb commented 3 years ago

my-directive is an angular "item", so when generating the module, Angular is aware of it. CUSTOM_ELEMENTS_SCHEMA tells Angular that the code might have components which are not defined in the module, and are external web components. (in our case it is stenciljs, but could be angular elements, Vue web components, Svelte, whatever...). When angular sees my-component which is a web component, compilation will fail with the message that it is an unknown element, and if it is an external web component you should use the CUSTOM_ELEMENTS_SCHEMA.

My directive is doing something like:

      const myEl = this.el.nativeElement.closest('my-component'); //this.el is the directive ElementRef
      // Do something with myEl, e.g. add or remove classes. 

So in order to test, I need to do a

MockRender(`<my-component> <div my-directive></div> </my-component>`);

I hope this clarifies, but let me know if not, and I will be happy to elaborate.

satanTime commented 2 years ago

Hi here too, I think the answer is similar to: https://github.com/ike18t/ng-mocks/issues/1642