Closed MatthieuNarcisi closed 4 years ago
Issues tagged with feature request are closed but tracked for reactions to gauge interest.
My opinion: Since Capacitor is framework agnostic, I think this should be a separate project/repo as it was done with capacitor react hooks https://github.com/ionic-team/ionic-react-hooks
I agree with you, it should be a separate project but I did not find a better place to talk about the feature.
I also wanted to make sure that it did not already existed as I took sometime to look for it but could not find anything on the web.
It seems a great idea. I just started a new project and it's boring to wrap every single plugins into an Angular services just in order to test my code.
In the interim, I wouldn't go to the extreme of creating a bunch of boring injectable services just in order to test your code.
You can just replace the items on Plugins
as such: https://github.com/ionic-team/iv-training-starter/blob/master/src/app/app.component.spec.ts#L11-L25
Use them in your test the usual way: https://github.com/ionic-team/iv-training-starter/blob/master/src/app/app.component.spec.ts#L34-L38
And just keep your code using the objects on Plugins
the way that it is: https://github.com/ionic-team/iv-training-starter/blob/master/src/app/app.component.ts#L17-L24
No services needed.
Totally agree that it would be nice to have them, though. It would make the testing more "natural", but it certainly isn't a requirement in many cases.
@kensodemann Thanks, I don't know why I thought they were const.
But finally, I start to love my injectable services (it's maybe my OCD side). I think, that to have my plugins injected in the constructor, is more readable/maintainable to know what a component does.
To better isolate the tests, and test the platform related behaviours, I ended up to inject the Plugins with InjectionToken, because the plugins are interfaces (intances), and not class. So I added the tokens like this:
import { InjectionToken } from "@angular/core";
import { AppPlugin, CameraPlugin, StatusBarPlugin } from "@capacitor/core";
import { Capacitor } from "@capacitor/core/dist/esm/definitions";
export const APP_PLUGIN = new InjectionToken<AppPlugin>('AppPlugin');
export const CAMERA_PLUGIN = new InjectionToken<CameraPlugin>('CameraPlugin');
export const STATUS_BAR_PLUGIN = new InjectionToken<StatusBarPlugin>('StatusBarPlugin');
export const CAPACITOR = new InjectionToken<Capacitor>('Capacitor');
Registered them in the module provider like this:
providers:[
....
{
provide: CAMERA_PLUGIN,
useValue: Plugins.Camera,
},
{
provide: APP_PLUGIN,
useValue: Plugins.App,
},
{
provide: STATUS_BAR_PLUGIN,
useValue: Plugins.StatusBar,
},
{
provide: CAPACITOR,
useValue: Capacitor,
}
]
And finally injected in the component / service constructor like this:
constructor(
@Inject(APP_PLUGIN) private app: AppPlugin,
@Inject(STATUS_BAR_PLUGIN) private statusBar: StatusBarPlugin,
@Inject(CAPACITOR) private capacitor: Capacitor,
) {
}
This way in the tests I can mock directly the injected plugins and do not relay on the dependencies. Be cause I use ng-mocks the result is like this:
beforeEach(() => {
// The result of MockBuilder should be returned.
return MockBuilder(AppComponent, AppModule);
});
beforeEach(() =>
MockInstance(CAPACITOR, () => ({
isPluginAvailable: () => true
})),
);
// necessary because not available on for the web plugin
beforeEach(() =>
MockInstance(STATUS_BAR_PLUGIN, () => ({
setBackgroundColor: jasmine.createSpy(),
setStyle: jasmine.createSpy()
})),
);
it('should initialize the app', async () => {
const fixture = MockRender(AppComponent);
const component = fixture.point.componentInstance;
const injector = fixture.point.injector;
await fixture.whenStable();
const statusBar = injector.get<StatusBarPlugin>(STATUS_BAR_PLUGIN);
expect(statusBar.setBackgroundColor).toHaveBeenCalled();
expect(statusBar.setStyle).toHaveBeenCalled();
expect(statusBar.setStyle).toHaveBeenCalledWith(jasmine.objectContaining({ style: StatusBarStyle.Dark }));
});
What do you think? Is there a better way?
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Capacitor, please create a new issue and ensure the template is fully filled out.
Feature Request
Describe the Feature Request
Services wrapper for Plugins on Angular (or other Frameworks) are not available. Preventing dependency injection and good testing.
Platform Support Requested
Describe Preferred Solution
Libraries for main frameworks (Angular, React, Vue) should be released, providing wrapping service to be able to inject the plugins in other classes to allow for testing and better maintainability (lazy loading, code analysis...)
Related Code
Service Example
Additional Context
I don't know if it is the right repository to post this issue, but I could not think of another one.