apollo-angular icon indicating copy to clipboard operation
apollo-angular copied to clipboard

Flush on TestOperation does not work if Query Document contains a Fragment

Open reicheltp opened this issue 8 months ago • 1 comments

Describe the bug

The ApolloTestingController removes all flushed fields, which are described in a fragment.

To Reproduce

Having the following query:

query GetBenefitOptions {
  benefits {
    ...BenefitOption
  }
}

fragment BenefitOption on Benefit {
  __typename
  id
  description

  price {
    price
  }
}

and code in the component:

public readonly options$: Observable<BenefitOptionFragment[]> = this.getBenefitOptions.watch().valueChanges.pipe(
    map((result) => result.data.benefits),
    tap((val) => console.log(JSON.stringify(val)))
  );

I am doing the following test case:

// The change of the inputs should trigger the query
    const op: TestOperation<GetBenefitOptionsQuery> = controller.expectOne(GetBenefitOptionsDocument);

    // Mock the GraphQL response
    op.flushData({
      __typename: 'Query',
      benefits: [
        {
          __typename: 'PrivateBenefit',
          id: 'benefit-1' as BenefitID,
          description: 'Basic Cleaning',
          price: { price: 50 },
        },
        {
          __typename: 'PrivateBenefit',
          id: 'benefit-2' as BenefitID,
          description: 'Premium Cleaning',
          price: { price: 100 },
        },
        {
          __typename: 'PrivateBenefit',
          id: 'benefit-3' as BenefitID,
          description: 'Deep Cleaning',
          price: { price: 150 },
        },
      ],
    });

The component logs:

[{}, {}, {}]

Changing the query to not using a fragment

query GetBenefitOptions($filter: BenefitsFilterInput!) {
  benefits {
    __typename
    id
    description

    price {
      price
    }
  }
}

let the component produce the expected output

[{"__typename":"PrivateBenefit","id":"benefit-1","description":"Basic Cleaning","price":{"price":50}},{"__typename":"PrivateBenefit","id":"benefit-2","description":"Premium Cleaning","price":{"price":100}},{"__typename":"PrivateBenefit","id":"benefit-3","description":"Deep Cleaning","price":{"price":150}}]

Expected behavior

TestingController will also work with fragments.

Environment:

├── @angular/[email protected]
├── @angular/[email protected] overridden
├── @apollo/[email protected]
├── [email protected]
├── [email protected]
└── [email protected]

Additional context

Using Karma to execute the tests.

Benefit is an interface.

reicheltp avatar Mar 14 '25 07:03 reicheltp

I digged a little bit deeper into this topic and discovered that this problem only occurs when using interfaces with fragment.

For the InMemoryCache it is mandatory to provide all possible types. Is there any way to tell the Test Executor that a fragment for an interface is valid for the actual implementation?

Alternatively, we can maybe tell apollo to ignore the actual types and just return everything we flushed? Will this break other stuff?

reicheltp avatar Mar 20 '25 07:03 reicheltp