Testing - Can't resolve all parameters for (ClassName)

前端 未结 4 1185
清歌不尽
清歌不尽 2020-11-30 11:04

Context

I created an ApiService class to be able to handle our custom API queries, while using our own serializer + other features.

ApiSer

相关标签:
4条回答
  • 2020-11-30 11:38

    [JEST and ANGULAR]

    Also, the problem may occur when you use an external module and you do not import it but use it on your service.

    Ex:

    import { TestBed } from '@angular/core/testing';
    import <ALL needed> from '@ngx-translate/core';
    
    import { SettingsService } from '../../../app/core/services/settings/settings.service';
    
    
    describe('SettingsService', () => {
      let service: SettingsService;
    
      beforeAll(() => {
        TestBed.configureTestingModule({
          providers: [
            SettingsService,
            <All needed>
          ]
        });
        service = TestBed.inject<SettingsService>(SettingsService);
      });
    
      it('should be created', () => {
        expect(service).toBeTruthy();
      });
    
    });
    

    Errors will get you nowhere ... But, if you do that this way:

    import { TestBed } from '@angular/core/testing';
    
    import { TranslateModule } from '@ngx-translate/core';
    
    import { SettingsService } from '../../../app/core/services/settings/settings.service';
    
    
    describe('SettingsService', () => {
      let service: SettingsService;
    
      beforeAll(() => {
        TestBed.configureTestingModule({
          imports: [TranslateModule.forRoot()], <---
          providers: [
            SettingsService
          ]
        });
        service = TestBed.inject<SettingsService>(SettingsService);
      });
    
      it('should be created', () => {
        expect(service).toBeTruthy();
      });
    
    });
    

    Problem disappears.

    0 讨论(0)
  • 2020-11-30 11:39

    The issue wasn't really solved in the chosen answer, which is really just a recommendation for writing tests, but rather in the comments, and you have to follow a link and search for it there. Since I had another issue with the same error, I'll add both solutions here.

    1. Solution to the OP's issue:

    If you have a barrel (index.ts or multi export file) like this:

    export * from 'my.component' // using my.service via DI
    export * from 'my.service'
    

    Then you could get an error like EXCEPTION: Can't resolve all parameters for MyComponent: (?).

    To fix it, you have to export the service before the component:

    export * from 'my.service'
    export * from 'my.component' // using my.service via DI
    
    1. Solution to my issue:

    The same error can happen due to a circular dependency which causes an undefined service import. To check, console.log(YourService) after importing it (in your test file - where the issue is happening). If it's undefined, you may have made an index.ts file (barrel) exporting both the service and the file using it (component/effect/whatever you're testing) - by importing the service from the index file where both are exported (making it full circle).

    Find that file and import the service you need directly from your.service.ts file instead of the index.

    0 讨论(0)
  • 2020-11-30 11:43

    It's because the Http service can't be resolved from the HttpModule, in a test environment. It is dependent on the platform browser. You shouldn't even be trying to to make XHR calls anyway during the tests.

    For this reason, Angular provides a MockBackend for the Http service to use. We use this mock backend to subscribe to connections in our tests, and we can mock the response when each connection is made.

    Here is a short complete example you can work off of

    import { Injectable } from '@angular/core';
    import { async, inject, TestBed } from '@angular/core/testing';
    import { MockBackend, MockConnection } from '@angular/http/testing';
    import {
      Http, HttpModule, XHRBackend, ResponseOptions,
      Response, BaseRequestOptions
    } from '@angular/http';
    
    @Injectable()
    class SomeService {
      constructor(private _http: Http) {}
    
      getSomething(url) {
    	return this._http.get(url).map(res => res.text());
      }
    }
    
    describe('service: SomeService', () => {
      beforeEach(() => {
    	TestBed.configureTestingModule({
    	  providers: [
    		{
    		  provide: Http, useFactory: (backend, options) => {
    			return new Http(backend, options);
    		  },
    		  deps: [MockBackend, BaseRequestOptions]
    		},
    		MockBackend,
    		BaseRequestOptions,
    		SomeService
    	  ]
    	});
      });
    
      it('should get value',
    	async(inject([SomeService, MockBackend],
    				 (service: SomeService, backend: MockBackend) => {
    
    	backend.connections.subscribe((conn: MockConnection) => {
    	  const options: ResponseOptions = new ResponseOptions({body: 'hello'});
    	  conn.mockRespond(new Response(options));
    	});
    
    	service.getSomething('http://dummy.com').subscribe(res => {
    	  console.log('subcription called');
    	  expect(res).toEqual('hello');
    	});
      })));
    });

    0 讨论(0)
  • 2020-11-30 11:58

    Using Jest?

    In case anyone gets here AND you're using Jest to test your Angular app (hopefully we're a growing minority), you will run into this error if you are not emitting decorators. You'll need to update your tsconfig.spec.json file so it looks like:

    {
      "extends": "../../tsconfig.json",
      "compilerOptions": {
        "emitDecoratorMetadata": true,
        "outDir": "../../out-tsc/spec",
        "types": [
          "jest",
          "node"
        ]
      },
      "files": [
      ],
      "include": [
        "**/*.spec.ts",
        "**/*.d.ts"
      ]
    }
    
    0 讨论(0)
提交回复
热议问题