console/integration-tests/tests/schema/metadata.spec.ts
2025-03-28 12:49:56 +01:00

199 lines
5.7 KiB
TypeScript

import { normalizeSupergraph } from 'testkit/graphql';
import { getServiceHost } from 'testkit/utils';
import type { SchemaBuilderApi } from '@hive/schema';
import { createTRPCProxyClient, httpLink } from '@trpc/client';
const host =
process.env['SCHEMA_SERVICE_HOST_OVERRIDE'] ||
(await getServiceHost('schema', 3002).then(r => `http://${r}`));
const client = createTRPCProxyClient<SchemaBuilderApi>({
links: [
httpLink({
url: host + `/trpc`,
fetch,
}),
],
});
describe('schema service can process metadata', async () => {
const result = await client.composeAndValidate.mutate({
type: 'federation',
native: true,
schemas: [
{
raw: /* GraphQL */ `
extend schema
@link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://specs.apollo.dev/federation/v2.3")
@link(url: "https://specs.graphql-hive.com/hive/v1.0", import: ["@meta"])
@meta(name: "schema", content: "user")
directive @meta(
name: String!
content: String!
) repeatable on SCHEMA | OBJECT | INTERFACE | FIELD_DEFINITION
type Query {
user: User @meta(name: "field", content: "user")
}
type User @meta(name: "type", content: "user") {
id: ID!
name: String @meta(name: "field", content: "User.name")
}
`,
source: 'user.graphql',
url: null,
},
{
raw: /* GraphQL */ `
extend schema
@link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://specs.apollo.dev/federation/v2.1")
@link(url: "https://specs.graphql-hive.com/hive/v1.0", import: ["@meta"])
@meta(name: "schema", content: "foo")
directive @meta(
name: String!
content: String!
) repeatable on SCHEMA | OBJECT | INTERFACE | FIELD_DEFINITION
type Query {
foo: String
}
`,
source: 'foo.graphql',
url: null,
},
],
external: null,
contracts: null,
});
test('@meta does not need to be in supergraph', () => {
expect(result.supergraph).toBeDefined();
expect(normalizeSupergraph(result.supergraph!)).toMatchInlineSnapshot(`
directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE
directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean, override: String, usedOverridden: Boolean) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
directive @join__implements(graph: join__Graph!, interface: String!) repeatable on INTERFACE | OBJECT
directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true, isInterfaceObject: Boolean! = false) repeatable on ENUM | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION
directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION
directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
enum join__Graph {
FOO_GRAPHQL @join__graph(name: "foo.graphql", url: "")
USER_GRAPHQL @join__graph(name: "user.graphql", url: "")
}
enum link__Purpose {
"""
\`EXECUTION\` features provide metadata necessary for operation execution.
"""
EXECUTION
"""
\`SECURITY\` features provide metadata necessary to securely resolve fields.
"""
SECURITY
}
type Query @join__type(graph: FOO_GRAPHQL) @join__type(graph: USER_GRAPHQL) {
foo: String @join__field(graph: FOO_GRAPHQL)
user: User @join__field(graph: USER_GRAPHQL)
}
type User @join__type(graph: USER_GRAPHQL) {
id: ID!
name: String
}
scalar join__FieldSet
scalar link__Import
schema @link(for: EXECUTION, url: "https://specs.apollo.dev/join/v0.3") @link(import: ["@meta"], url: "https://specs.graphql-hive.com/hive/v1.0") @link(url: "https://specs.apollo.dev/link/v1.0") {
query: Query
}
`);
});
test('metadata is a union from schema, type, and field @meta', () => {
expect(result.schemaMetadata).toMatchInlineSnapshot(`
{
Query.foo: [
{
content: foo,
name: schema,
source: foo.graphql,
},
],
Query.user: [
{
content: user,
name: field,
source: user.graphql,
},
{
content: user,
name: schema,
source: user.graphql,
},
],
User.id: [
{
content: user,
name: type,
source: user.graphql,
},
{
content: user,
name: schema,
source: user.graphql,
},
],
User.name: [
{
content: User.name,
name: field,
source: user.graphql,
},
{
content: user,
name: type,
source: user.graphql,
},
{
content: user,
name: schema,
source: user.graphql,
},
],
}
`);
});
test('metadataAttributes includes all used metadata names and content', () => {
expect(result.metadataAttributes).toMatchInlineSnapshot(`
{
field: [
user,
User.name,
],
schema: [
user,
foo,
],
type: [
user,
],
}
`);
});
});