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

Feedback for “Testing” - Please document how to handle generated GQL classes in Tests #1903

Open
apazureck opened this issue Jan 30, 2023 · 4 comments

Comments

@apazureck
Copy link

Hi,

I am currently struggleing using my generated GQLs for testing and cannot find any solution when searching online.

I have a component, which depends on a service using the generated GQL with Apollo Codegen:

Test:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ApolloTestingModule } from 'apollo-angular/testing';

import { SettingsComponent } from './settings.component';

describe('SettingsComponent', () => {
  let component: SettingsComponent;
  let fixture: ComponentFixture<SettingsComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [SettingsComponent],
      imports: [ApolloTestingModule],
    }).compileComponents();

    fixture = TestBed.createComponent(SettingsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Component:

export class SettingsComponent implements OnDestroy, OnInit {
  constructor(
    private settingsService: SettingsService,
    private snackBar: MatSnackBar
  ) {}
  // omitted...

Service:

@Injectable({
  providedIn: 'root',
})
export class SettingsService implements OnDestroy {
  constructor(
    private fullConfigurationQuery: FullConfigurationGQL,
    private changeConfigMutation: ChangeConfigGQL,
    private configChanged: ConfigChangedGQL
  ) {}
// omitted...

FullConfigurationGQL:

@Injectable({
    providedIn: 'root'
  })
  export class FullConfigurationGQL extends Apollo.Query<FullConfigurationQuery, FullConfigurationQueryVariables> {
    override document = FullConfigurationDocument;
    
    constructor(apollo: Apollo.Apollo) {
      super(apollo);
    }
  }
// omitted....

So when I use the ApolloTestingModule I would expect it has some kind of provider for Apollo. But it does not seem so. This is my test error:

Error: NG0202: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid.
This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.

Please check that 1) the type for the parameter at index 0 is correct and 2) the correct Angular decorators are defined for this class and its ancestors.

As you can see the service as well as the GQL have those tags, but the Apollo class does not. So how can I provide the mock to be used by the generated GQL class? It would be nice to use the controller in the long term for evaluating the queries.

And I know, I could and definitly should mock the service in the first place (which I will do in the future), but that would only postpone my problem. I would like to use the Apollo Mock there, if possible.

How can I do this?

If I figure something out I'll be happy to share it here and woudl gladly update the documentation.

Cheers!

@ghost
Copy link

ghost commented Sep 21, 2023

@apazureck
Did you ever figure out a way to fix this?

We've just run into the exact same problem with a newly generated angular project.

@vampyr09
Copy link

vampyr09 commented Nov 7, 2023

It's far from perfect but what will work is to provide the GQL in your TestBed:

import { Apollo } from 'apollo-angular';

TestBed.configureTestingModule({
  providers: [
    {
      provide: FullConfigurationGQL,
      useFactory: (apollo: Apollo) => new FullConfigurationGQL(apollo)
    }
  ]
});

You could write yourself a Wrapper, this will at least remove some of the boilerplate (if you need to provide multiple GQL at the same time)

import { Apollo, Query } from 'apollo-angular';

type ApolloNewable = new (apollo: Apollo) => Query;

function provideGQL(...gqlProviders: ApolloNewable[]) {
  return gqlProviders.map(gql => ({
    provide: gql,
    useFactory: (apollo: Apollo) => new gql(apollo)
  }));
}

TestBed.configureTestingModule({
  providers: [
    ...provideGQL(FullConfigurationGQL),
  ]
});

But in my opinion it is still sad that this might be necessary.

@Butterbluemchen
Copy link

I had the same problem. As a workaround I changed the imports in the generated file like this:

import { gql, Apollo as ApolloClient } from 'apollo-angular';
import * as Apollo from 'apollo-angular';

and then for every constructor:
constructor(apollo: ApolloClient)

You might create a script which runs after the code generation, to do this for you.

@lodeli-lulu
Copy link

I had the same problem too. I'm using Jest as test framework with jest-preset-angular.

I could solve it by changing the include array in the tsconfig.spec.json from:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    // Your compiler options
  },
  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}

to this:

{
 "extends": "./tsconfig.json",
 "compilerOptions": {
   // Your compiler options
 },
 "include": ["src/**/*.ts"] // Optionally you can still use `src/**/*.spec.ts` and `src/**/*.d.ts` and add the path to the graphql-codegen generated file.
}

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

4 participants