artemis icon indicating copy to clipboard operation
artemis copied to clipboard

Fragments: The superclass, '<name>FragmentMixin', has no unnamed constructor that takes no arguments

Open tuanvugoodmoney opened this issue 3 years ago • 19 comments

Before reporting a bug, please test the beta branch!

Bug description

I have a fragment that with direct fields except __typename and a union. The fragment and query is generated successfully, but when I write a unit test, I get the following errors while loading the unit tests. The query and fragment runs successfully on Apollo Graph explorer.

Errors

Failed to load "test/graphql_gateway_client_inquiry_test.dart":
lib/src/graphql/graphql.graphql.dart:3251:7: Error: The superclass, 'InquiryFragmentMixin', has no unnamed constructor that takes no arguments.
class InquiryFragmentMixin$Inquiry extends InquiryFragmentMixin
      ^
lib/src/graphql/graphql.graphql.dart:3272:7: Error: The superclass, 'InquiryFragmentMixin', has no unnamed constructor that takes no arguments.
class InquiryFragmentMixin$InquiryNotFoundError extends InquiryFragmentMixin
      ^
lib/src/graphql/graphql.graphql.dart:3290:7: Error: The superclass, 'InquiryFragmentMixin', has no unnamed constructor that takes no arguments.
class InquiryFragmentMixin$ServiceUnavailableError extends InquiryFragmentMixin
      ^
lib/src/graphql/graphql.graphql.dart:3308:7: Error: The superclass, 'InquiryFragmentMixin', has no unnamed constructor that takes no arguments.
class InquiryFragmentMixin$InquiryResumeFailedError extends InquiryFragmentMixin

Specs

Artemis version: 7.1.1-beta.1

build.yaml:
targets:
  $default:
    sources:
      - lib/**
      - lib/src/graphql/**
      - lib/src/graphql/schema.graphql
  graphql_gateway:
    builders:
      source_gen|combining_builder:
        options:
          ignore_for_file:
            - public_member_api_docs
            - lines_longer_than_80_chars
            - constant_identifier_names
      artemis:
        options:
          fragments_glob: lib/src/graphql/fragments/*.fragment.graphql
          schema_mapping:
            - schema: lib/src/graphql/schema.graphql
              queries_glob: lib/src/graphql/queries/**.graphql
              output: lib/src/graphql/graphql.dart
          scalar_mapping:
            - graphql_type: PhoneNumber
              dart_type: String
            - graphql_type: EmailAddress
              dart_type: String
            - graphql_type: DateTime
              dart_type: DateTime
            - graphql_type: PostalCode
              dart_type: String
      json_serializable:
        options:
          include_if_null: false

Artemis output:
flutter pub run build_runner build --verbose
[ +119 ms] executing: sysctl hw.optional.arm64
[  +24 ms] Exit code 1 from: sysctl hw.optional.arm64
[        ] sysctl: unknown oid 'hw.optional.arm64'
[  +13 ms] executing: [/Applications/Flutter/beta/] git -c log.showSignature=false log -n 1 --pretty=format:%H
[  +52 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
[        ] d79295af24c3ed621c33713ecda14ad196fd9c31
[        ] executing: [/Applications/Flutter/beta/] git tag --points-at d79295af24c3ed621c33713ecda14ad196fd9c31
[ +198 ms] Exit code 0 from: git tag --points-at d79295af24c3ed621c33713ecda14ad196fd9c31
[        ] 2.2.2
[   +7 ms] executing: [/Applications/Flutter/beta/] git rev-parse --abbrev-ref --symbolic @{u}
[  +18 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{u}
[        ] origin/stable
[        ] executing: [/Applications/Flutter/beta/] git ls-remote --get-url origin
[  +17 ms] Exit code 0 from: git ls-remote --get-url origin
[        ] https://github.com/flutter/flutter.git
[ +133 ms] executing: [/Applications/Flutter/beta/] git rev-parse --abbrev-ref HEAD
[  +26 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[   +1 ms] stable
[   +9 ms] executing: sw_vers -productName
[  +21 ms] Exit code 0 from: sw_vers -productName
[   +1 ms] macOS
[        ] executing: sw_vers -productVersion
[  +21 ms] Exit code 0 from: sw_vers -productVersion
[        ] 11.4
[        ] executing: sw_vers -buildVersion
[  +24 ms] Exit code 0 from: sw_vers -buildVersion
[        ] 20F71
[  +97 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[   +5 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[ +173 ms] Artifact Instance of 'MaterialFonts' is not required, skipping update.
[        ] Artifact Instance of 'GradleWrapper' is not required, skipping update.
[        ] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[        ] Artifact Instance of 'FlutterSdk' is not required, skipping update.
[        ] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FontSubsetArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'PubDependencies' is not required, skipping update.
[  +19 ms] executing: /Applications/Flutter/beta/bin/cache/dart-sdk/bin/pub run build_runner build --verbose
[INFO] Entrypoint:Generating build script...
[INFO] Entrypoint:Generating build script completed, took 650ms

[INFO] BuildDefinition:Initializing inputs
[INFO] BuildDefinition:Reading cached asset graph...
[INFO] BuildDefinition:Reading cached asset graph completed, took 80ms

[INFO] BuildDefinition:Checking for updates since last build...
[INFO] BuildDefinition:Checking for updates since last build completed, took 498ms

[INFO] Build:Running build...
[INFO] Build:Running build completed, took 20ms

[INFO] Build:Caching finalized dependency graph...
[INFO] Build:Caching finalized dependency graph completed, took 44ms

[INFO] Build:Succeeded after 78ms with 0 outputs (0 actions)

[+3945 ms] "flutter run" took 4,186ms.
[   +5 ms] Running shutdown hooks
[        ] Shutdown hooks complete
[        ] exiting with code 0
GraphQL schema:
union InquiryResult = Inquiry | InquiryNotFoundError | InquiryResumeFailedError | ServiceUnavailableError
GraphQL query:
fragment inquiryResultFragment on InquiryResult {
  __typename
  ... on Inquiry {
    id
    status
    accessToken
  }
  ... on InquiryNotFoundError {
    message
  }
  ... on ServiceUnavailableError {
    message
  }
  ... on InquiryResumeFailedError {
    message
  }
}


query getInquiryById($inquiryById: ID!) {
  user {
    inquiryBy(id: $inquiryById) {
      ...inquiryResultFragment
    }
  }
}

tuanvugoodmoney avatar Jul 19 '21 18:07 tuanvugoodmoney

Hi @tuanvugoodmoney could you add some code from graphql_gateway_client_inquiry_test.dart so we can reproduce the issue

vasilich6107 avatar Jul 20 '21 07:07 vasilich6107

import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';

late GraphQLClient graphQLClient;
  late GraphQLGatewayClient graphQLGatewayClient;

  setUpAll(() {
    registerFallbackValue<QueryOptions>(FakeQueryOptions());
  });

  setUp(() {
    graphQLClient = MockGraphQLClient();
    graphQLGatewayClient = GraphQLGatewayClient(
      graphQLClient: graphQLClient,
    );
  });


test('invokes query with correct query options', () async {
    final result = MockQueryResult();
    when(() => result.hasException).thenReturn(false);
    when(() => result.data).thenReturn(data);
    final queryCalls = <QueryOptions?>[];
    when(() => graphQLClient.query(any())).thenAnswer((invocation) async {
      queryCalls.add(invocation.positionalArguments.first);
      return result;
    });

    await graphQLGatewayClient.getInquiryById(inquiryId: 'inquiryId');

    expect(queryCalls.length, 1);
    expect(
      queryCalls.first!.document,
      GetInquiryByIdQuery(
        variables: GetInquiryByIdArguments(
          inquiryById: 'inquiryById',
        ),
      ).document,
    );
    expect(queryCalls.first!.variables, const <String, dynamic>{
      'inquiryById': 'inquiryId',
    });
    expect(queryCalls.first!.fetchPolicy, FetchPolicy.noCache);
  });

tuanvugoodmoney avatar Jul 20 '21 16:07 tuanvugoodmoney

@tuanvugoodmoney I do not see here anything related to generated code... This file does not imports any implementation from generated code

Where this error come from? Is there any stacktrace?

vasilich6107 avatar Jul 20 '21 18:07 vasilich6107

This code import only two libraries test and mocktail. It should still work fine if you delete everything related to generated code. Unless you posted limited version of file...

vasilich6107 avatar Jul 20 '21 18:07 vasilich6107

I'll work on creating a new repo to reproduce the problem

tuanvugoodmoney avatar Jul 20 '21 19:07 tuanvugoodmoney

Thanks

vasilich6107 avatar Jul 20 '21 19:07 vasilich6107

@vasilich6107 See this repository. My original project had analysis turned off for all generated graphql files so I didn't see compilation errors. In this new project, the generated graphql.graqhql.dart actually has a compilation error, see screenshot. In the same repo, you can see the user fragment generates normally.

If you try to run the test, the original error referenced in this ticket shows up, due to compilation error.

Screen Shot 2021-07-21 at 10 53 17 AM

tuanvugoodmoney avatar Jul 21 '21 18:07 tuanvugoodmoney

Thanks for your help

vasilich6107 avatar Jul 21 '21 19:07 vasilich6107

Will try to address the issue this week

vasilich6107 avatar Jul 25 '21 08:07 vasilich6107

Hi @tuanvugoodmoney Sorry for not paying proper attention to this bug. Will try to address it in one week

vasilich6107 avatar Aug 13 '21 19:08 vasilich6107

Hi @tuanvugoodmoney

For now I can only suggest you to write

query getInquiryById($inquiryById: ID!) {
  user {
    inquiryBy(id: $inquiryById) {
      __typename
      ... on Inquiry {
        id
      }
      ... on InquiryNotFoundError {
        message
      }
      ... on ServiceUnavailableError {
        message
      }
      ... on InquiryResumeFailedError {
        message
      }
    }
  }
}

without using the fragment

vasilich6107 avatar Aug 30 '21 09:08 vasilich6107

@tuanvugoodmoney you can also write like this to incorporate fragments

query getInquiryById($inquiryById: ID!) {
  user {
    ...User
  }
}

fragment User on User {
  inquiryBy(id: $inquiryById) {
    __typename
    ... on Inquiry {
      id
    }
    ... on InquiryNotFoundError {
      message
    }
    ... on ServiceUnavailableError {
      message
    }
    ... on InquiryResumeFailedError {
      message
    }
  }
}

vasilich6107 avatar Aug 30 '21 09:08 vasilich6107

Any update on this issue? I'm seeing the same compiler errors in generated code:

image

The issue seems to be caused by nested fragments within either a union or interface.

jjoelson avatar Oct 07 '21 21:10 jjoelson

@jjoelson you can apply the workaround that I suggested in my previous comment

vasilich6107 avatar Oct 08 '21 05:10 vasilich6107

@vasilich6107 Thank you for the quick response! I am able to work around it for now by restructuring my fragments.

I might dive a bit into the Artemis code to see if I can figure out the issue, so I'll comment here if I find anything useful.

jjoelson avatar Oct 08 '21 16:10 jjoelson

This is also affecting me :(

I have the nested fragment inside of an interface, and I get a similar extends XYZMixin compile error.

Going to use the workaround to avoid the inner fragment, but it's definitely not as clean

cody1024d avatar Nov 13 '21 20:11 cody1024d

@cody1024d unfortunately there is no solution for now except the reorganizing fragments structure

vasilich6107 avatar Nov 13 '21 21:11 vasilich6107

@vasilich6107 No problem. It is not the end of the world! Thank you for this awesome project!

cody1024d avatar Nov 13 '21 21:11 cody1024d

Any updates on this issue?

I would like to use a shared mixin from a union to render a UI for all queries that return the data, so the workaround above results in a type error.

Example:

// schema.grapqhl
interface InsightTabFields {
	id: ID!
	name: String!
}

type Insight implements InsightTabFields {
	id: ID!
	name: String!
	insight: String!
}

type Image implements InsightTabFields {
	id: ID!
	name: String!
	image: String!
}

type Game {
	users: [User!]!
	insights: [InsightTab!]!
	otherGameData: OtherGameData!
}

type User {
	insights: [InsightTab!]!
	otherUserData: OtherUserData!
}

// fragments.graphql
fragment InsightTab on InsightTab {
	__typename
	... on Insight {
		__typename
		...Insight
	}
	... on Image {
		__typename
		...Image
	}
}

fragment Insight on Insight {
	id
	name
	insight
}

fragment Image on Image {
	id
	name
	image
}

fragment User on User {
	__typename
	insights: {
		__typename
		...InsightTab
	}
	otherUserData: {
		__typename
		...otherUserData
	}
}

fragment Game on Game {
	__typename
	insights: {
		__typename
		...InsightTab
	}
	otherGameData: {
		__typename
		...otherGameData
	}
}


// queries
query GetUserInsightTabs($userId: ID!) {
	getUserInsightTabs(userId: $userId) {
		__typename
		...User
	}
}

query GetMatchInsightTabs($matchId: ID!) {
	getMatchInsightTabs(matchId: $matchId) {
		__typename
		...Game
	}
}

We're using the same UI widget to show all insights. So the workaround posted results in the error UserMixin$InsightTab is not of type GameMixin$InsightTab. I was hoping to make the widget expect InsightTabMixin so both cases work. Is there a fix or other workaround I should try?

apackin avatar Mar 28 '22 23:03 apackin