I've got a component that I'm trying to unit test but I keep getting these errors, depending on my import statements:
Error: Cannot resolve all parameters for 'MyComponent'(undefined, FormBuilder).
TypeError: Cannot read property 'toString' of undefined
My component takes 2 parameters, one the FormBuilder and one a custom service, that must be injected:
import {MyService} from '../';
@Component({
...,
providers: [MyService]
})
class MyComponent {
constructor(service: MyService, fb: FormBuilder) { ... }
...
}
And my unit test is setup as follows:
import {MyComponent} from './';
import {MyService} from '../';
describe('Component: MyComponent', () => {
let builder: TestComponentBuilder;
beforeEachProviders(() => [
MyService,
MyComponent
]);
beforeEach(inject([TestComponentBuilder], function (tcb: TestComponentBuilder) {
builder = tcb;
}));
it('should inject the component', inject([MyComponent],
(component: MyComponent) => {
expect(component).toBeTruthy();
})
);
}
The imports seem to be the problem, since I'm trying to use barrels:
|
|- my-component
| |- index.ts
| |- my.component.ts
| |- my.component.spec.ts
|
|- my-service
| |- index.ts
| |- my.service.ts
|
|- index.ts
Inside my index.ts files, I'm doing:
export * from '<filename>';
export * from '<directory>';
as appropriate.
However, when I change the imports in the unit test AND component to reference the service file directly, the unit test works.
import {MyService} from '../my-service/my.service';
I'm using angular-cli in this project and SystemJS is being configured with the generated config file from that:
...
const barrels: string[] = [
...,
// App specific barrels.
'app',
'app/my-service',
'app/my-component'
/** @cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
cliSystemConfigPackages[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'@angular': 'vendor/@angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js'
},
packages: cliSystemConfigPackages
});
...
It seems that when I import from the barrels, the component and service definitions aren't loaded ahead of the unit test code. The application itself will transpile and run, either way.
Sorry if this is asking a broad question, but I'm still pretty new to barrels and SystemJS and I don't know how to narrow the scope further:
Is this a bug with SystemJS/Jasmine/TypeScript/Angular2 or am I doing something wrong in my setup?
I'd have to see the contents of the barrels you're importing from to know for sure but it sounds like you need to change the ordering of exports within your barrel.
An issue in the angular2 repo exists here: https://github.com/angular/angular/issues/9334
If a component (A) imports and uses a service/component (B) from a barrel containing the exports of both A and B, and A appears before B in the barrel, the imported value of B is undefined.
So in your case, if you modify your root index.ts to the following, you should be able to import from your barrels.
export * from my-service;
export * from my-component;