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

How to override Angular component method? #8215

Closed
dereklin opened this issue Sep 27, 2019 · 4 comments
Closed

How to override Angular component method? #8215

dereklin opened this issue Sep 27, 2019 · 4 comments

Comments

@dereklin
Copy link

Let's say I have an Angular component with a getDataFromBackend method.

In my storybook I want getDataFromBackend to always return a mock.

Is there a way to override this method?

@kroeder
Copy link
Member

kroeder commented Sep 28, 2019

Mh I don't think overriding is possible. What you are trying to achieve is kind of the same as trying to mock things for unit tests. Without seeing your code I'd try something like this

@Injectable()
export class DataBackendService {
  getDataFromBackend() {
    // do the network request here
  }
}

@Component({
  ...
})
export class SmartComponent {
  constructor(private dataBackendService: DataBackendService) {}

  getData() {
    return this.dataBackendService.getDataFromBackend();
  }
}

In your story you can now do this

class StubService {
  getDataFromBackend() {
    return { /* static test data here */ }
  }
}

storiesOf('YourStory', module).addDecorator(
    moduleMetadata({
      provides: [
        { provide: DataBackendService, useClass: StubService }
      ]
      declarations: [WithStoreComponent],
    })

What happens here? Well Angular magic! You can replace a service with another implementation
See https://angular.io/guide/dependency-injection-providers

Here's a stackblitz example https://stackblitz.com/edit/angular-6xhma8ng-dep-providers?file=src/app/app.component.ts

@dereklin
Copy link
Author

Unfortunately the service is not injected in in this case. I have no control of the component.

Right now I am using a proxy approach similar to this: #208 (comment)

But even with the proxy approach, it would be better to be able to do proxy per story instead of per the whole project.

In Jasmine, we can use spyOn to override specific methods when testing. It would be nice to have similar mechanism in storybook.

@kroeder
Copy link
Member

kroeder commented Sep 28, 2019

Storybook just wraps an Angular host and puts a story inside this wrapper. You are of course free to instantiate your component using the angular ComponentFactory or wrap it inside a demo component. Jasmine tests also instantiate the component in order to give you an instance that you can spyOn

Maybe this helps?

@Component({
  template: `<your-actual-component></your-actual-component>`
})
class DemoWrapperComponent {

  @ViewChild(YourActualComponent, { static: false }) componentRef: YourActualComponent

  ngOnInit() {
    componentRef['methodYouWantToOverride'] = () => { return "do crazy stuff" };
  }
}

Haven't tested it, not sure if it works!

@dereklin
Copy link
Author

@kroeder That works! Thanks so much for your help!!

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

No branches or pull requests

3 participants