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

Unable to override directive for standalone component #668

Open
Martinspire opened this issue Sep 6, 2024 · 2 comments
Open

Unable to override directive for standalone component #668

Martinspire opened this issue Sep 6, 2024 · 2 comments

Comments

@Martinspire
Copy link

Martinspire commented Sep 6, 2024

Is this a regression?

Yes

Description

I began migrating my application to standalone components and I've run into issues overriding various imports.

I have an example with overriding CdkCopyToClipboard directive and I simply cannot figure out why it isn't working or what setup the componentfactory needs to make it work. The documentation is kinda lacking in this regard. Tried various ways of doing it, even reverting back to testbed isn't really working out since the syntax to override stuff is also unclear there.

So the test has a mock directive that instead of copying to clipboard, puts the value in a string. Not the best way, but the functionality isn't really the point. The component itself has a button that we show if there's anything to copy if there's text on the component input.

When moving to standalone components, there are now 3 items imported, 2 are material related, 1 is CDK related and it seems that the cdk one is always being used normally instead of taking the mocked directive.

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/stackblitz-starters-um7c3g?file=src%2Fcomponents%2Fcopy-to-clipboard.component.spectator.spec.ts

Please provide the exception or error you saw

The value is never overridden

Please provide the environment you discovered this bug in

Angular 18, Spectator 19, NgMocks 14, Karma/Jasmine unit testing

Anything else?

Overall the documentation (also on Angular's side) is very unclear on how stuff should be overridden. I've tried a few attempts with the OverrideDirectives and OverrideModules variants, but from what I gather, it seems that is mostly made to override providers and this isn't a provider issue. I could never make it work with overriding the cdk for the mocked version.

Seeing that standalone is becoming the default in Angular 19, it would be helpful if the standalone documentation is a bit extended, but I think its also helpful if the issue I'm having is answered.

Do you want to create a pull request?

No

Copy link

stackblitz bot commented Sep 6, 2024

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

@Martinspire
Copy link
Author

Martinspire commented Sep 11, 2024

Ok so I finally fixed the spectator setup:


let clipboardResult = '';
@Directive({ selector: '[cdkCopyToClipboard]', standalone: true }) // don't forget standalone here
class MockCdkCopyToClipboard {
  // text to copy to clipboard
  @Input() set cdkCopyToClipboard(value: string) {
    console.log('text copied', value);
    clipboardResult = value;
  }
}

describe('CopyToClipboardComponent', () => {

let spectator: Spectator<CopyToClipboardComponent>;
  const createComponent = createComponentFactory({ // this is from ngneat spectator
    component: CopyToClipboardComponent,
    imports: [ // imports instead of declarations
      MockComponent(MatIcon),
      MockComponent(MatIconButton),
    ],
    overrideComponents: [ // this overrideComponents to override a part of this compnoent
      [
        CopyToClipboardComponent,
        {
          remove: { imports: [CdkCopyToClipboard] },
          add: { imports: [MockCdkCopyToClipboard] }, // finally replacing the import
        },
      ],
    ],
  });

And for when its not a standalone dependency:

describe('MapComponent', () => {
  let component: MapComponent;
  let spectator: Spectator<MapComponent>;

  const createComponent = createComponentFactory({ // again with spectator + ngmocks
    component: MapComponent,
    imports: [SomeDependencyMapModule], // do include the module
    overrideModules: [ // override the module contents
      [
        SomeDependencyMapModule,
        {
          remove: {
            exports: [DependencyMapComponent], // 
            declarations: [DependencyMapComponent],
            providers: [SomeServiceItNeeds],
          },
          add: {
            exports: [MockDependencyMapComponent],
            declarations: [MockDependencyMapComponent],
            providers: [MockSomeServiceItNeeds],
          },
        },
      ],
    ],
  });
});

And while that is nice to see, I still don't get why Spectator doesn't let us override this normally as before. I would imagine that this is still a bug that should not require overrideComponents, but having just a different list of imports should be fine (or at least an improvement).

What the module override tought me, is that you really need to override everything in the module that it is registering. Which seems like more of a hassle than I thought it would be. Still, having working tests is a plus.

Glad to at least have a workaround for it. So I can finally finish the migration.

I hope somebody will see this and helps their issue out. I think the documentation can be improved in this area but at least we have working code now.

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

No branches or pull requests

1 participant