mirror of
https://github.com/strapi/strapi.git
synced 2025-12-25 22:23:10 +00:00
add possibility to set a relation "private"
Signed-off-by: Pierre Noël <pierre.noel@strapi.io>
This commit is contained in:
parent
65a3e83ee3
commit
1227bfeba4
@ -18,9 +18,9 @@ const uploadImg = () => {
|
||||
describe.each([
|
||||
[
|
||||
'CONTENT MANAGER',
|
||||
'/content-manager/explorer/application::withdynamiczone.withdynamiczone',
|
||||
'/content-manager/explorer/application::withdynamiczonemedia.withdynamiczonemedia',
|
||||
],
|
||||
['GENERATED API', '/withdynamiczones'],
|
||||
['GENERATED API', '/withdynamiczonemedias'],
|
||||
])('[%s] => Not required dynamiczone', (_, path) => {
|
||||
beforeAll(async () => {
|
||||
const token = await registerAndLogin();
|
||||
@ -61,17 +61,9 @@ describe.each([
|
||||
},
|
||||
});
|
||||
|
||||
await modelsUtils.createContentTypeWithType(
|
||||
'withdynamiczone',
|
||||
'dynamiczone',
|
||||
{
|
||||
components: [
|
||||
'default.single-media',
|
||||
'default.multiple-media',
|
||||
'default.with-nested',
|
||||
],
|
||||
}
|
||||
);
|
||||
await modelsUtils.createContentTypeWithType('withdynamiczonemedia', 'dynamiczone', {
|
||||
components: ['default.single-media', 'default.multiple-media', 'default.with-nested'],
|
||||
});
|
||||
|
||||
rq = authRq.defaults({
|
||||
baseUrl: `http://localhost:1337${path}`,
|
||||
@ -82,7 +74,7 @@ describe.each([
|
||||
await modelsUtils.deleteComponent('default.with-nested');
|
||||
await modelsUtils.deleteComponent('default.single-media');
|
||||
await modelsUtils.deleteComponent('default.multiple-media');
|
||||
await modelsUtils.deleteContentType('withdynamiczone');
|
||||
await modelsUtils.deleteContentType('withdynamiczonemedia');
|
||||
}, 60000);
|
||||
|
||||
describe('Contains components with medias', () => {
|
||||
|
||||
@ -18,26 +18,20 @@ module.exports = {
|
||||
return ctx.send({ error }, 400);
|
||||
}
|
||||
|
||||
const contentTypeService =
|
||||
strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
const contentTypeService = strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
|
||||
const contentTypes = Object.keys(strapi.contentTypes)
|
||||
.filter(uid => {
|
||||
if (uid.startsWith('strapi::')) return false;
|
||||
if (uid === 'plugins::upload.file') return false; // TODO: add a flag in the content type instead
|
||||
|
||||
if (
|
||||
kind &&
|
||||
_.get(strapi.contentTypes[uid], 'kind', 'collectionType') !== kind
|
||||
) {
|
||||
if (kind && _.get(strapi.contentTypes[uid], 'kind', 'collectionType') !== kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.map(uid =>
|
||||
contentTypeService.formatContentType(strapi.contentTypes[uid])
|
||||
);
|
||||
.map(uid => contentTypeService.formatContentType(strapi.contentTypes[uid]));
|
||||
|
||||
ctx.send({
|
||||
data: contentTypes,
|
||||
@ -53,8 +47,7 @@ module.exports = {
|
||||
return ctx.send({ error: 'contentType.notFound' }, 404);
|
||||
}
|
||||
|
||||
const contentTypeService =
|
||||
strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
const contentTypeService = strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
|
||||
ctx.send({ data: contentTypeService.formatContentType(contentType) });
|
||||
},
|
||||
@ -71,8 +64,7 @@ module.exports = {
|
||||
try {
|
||||
strapi.reload.isWatching = false;
|
||||
|
||||
const contentTypeService =
|
||||
strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
const contentTypeService = strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
|
||||
const component = await contentTypeService.createContentType({
|
||||
contentType: body.contentType,
|
||||
@ -112,8 +104,7 @@ module.exports = {
|
||||
try {
|
||||
strapi.reload.isWatching = false;
|
||||
|
||||
const contentTypeService =
|
||||
strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
const contentTypeService = strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
|
||||
const component = await contentTypeService.editContentType(uid, {
|
||||
contentType: body.contentType,
|
||||
@ -139,8 +130,7 @@ module.exports = {
|
||||
try {
|
||||
strapi.reload.isWatching = false;
|
||||
|
||||
const contentTypeService =
|
||||
strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
const contentTypeService = strapi.plugins['content-type-builder'].services.contenttypes;
|
||||
|
||||
const component = await contentTypeService.deleteContentType(uid);
|
||||
|
||||
|
||||
@ -35,5 +35,6 @@ module.exports = (obj, validNatures) => {
|
||||
.test(isValidName)
|
||||
.nullable(),
|
||||
targetColumnName: yup.string().nullable(),
|
||||
private: yup.boolean().nullable(),
|
||||
};
|
||||
};
|
||||
|
||||
@ -60,18 +60,12 @@ function createSchemaBuilder({ components, contentTypes }) {
|
||||
|
||||
// init temporary ContentTypes
|
||||
Object.keys(contentTypes).forEach(key => {
|
||||
tmpContentTypes.set(
|
||||
contentTypes[key].uid,
|
||||
createSchemaHandler(contentTypes[key])
|
||||
);
|
||||
tmpContentTypes.set(contentTypes[key].uid, createSchemaHandler(contentTypes[key]));
|
||||
});
|
||||
|
||||
// init temporary components
|
||||
Object.keys(components).forEach(key => {
|
||||
tmpComponents.set(
|
||||
components[key].uid,
|
||||
createSchemaHandler(components[key])
|
||||
);
|
||||
tmpComponents.set(components[key].uid, createSchemaHandler(components[key]));
|
||||
});
|
||||
|
||||
return {
|
||||
@ -120,12 +114,14 @@ function createSchemaBuilder({ components, contentTypes }) {
|
||||
columnName,
|
||||
dominant,
|
||||
autoPopulate,
|
||||
private: isPrivate,
|
||||
} = attribute;
|
||||
|
||||
const attr = {
|
||||
unique: unique === true ? true : undefined,
|
||||
columnName: columnName || undefined,
|
||||
configurable: configurable === false ? false : undefined,
|
||||
private: isPrivate === true ? true : undefined,
|
||||
autoPopulate,
|
||||
};
|
||||
|
||||
|
||||
@ -16,8 +16,7 @@ const GraphQLLong = require('graphql-type-long');
|
||||
const Time = require('../types/time');
|
||||
const { toSingular, toInputName } = require('./naming');
|
||||
|
||||
const isScalarAttribute = ({ type }) =>
|
||||
type && !['component', 'dynamiczone'].includes(type);
|
||||
const isScalarAttribute = ({ type }) => type && !['component', 'dynamiczone'].includes(type);
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
@ -90,9 +89,7 @@ module.exports = {
|
||||
typeName =
|
||||
action === 'update'
|
||||
? `edit${_.upperFirst(toSingular(globalId))}Input`
|
||||
: `${_.upperFirst(toSingular(globalId))}Input${
|
||||
required ? '!' : ''
|
||||
}`;
|
||||
: `${_.upperFirst(toSingular(globalId))}Input${required ? '!' : ''}`;
|
||||
}
|
||||
|
||||
if (repeatable === true) {
|
||||
@ -104,9 +101,7 @@ module.exports = {
|
||||
if (attribute.type === 'dynamiczone') {
|
||||
const { required } = attribute;
|
||||
|
||||
const unionName = `${modelName}${_.upperFirst(
|
||||
_.camelCase(attributeName)
|
||||
)}DynamicZone`;
|
||||
const unionName = `${modelName}${_.upperFirst(_.camelCase(attributeName))}DynamicZone`;
|
||||
|
||||
let typeName = unionName;
|
||||
|
||||
@ -202,9 +197,7 @@ module.exports = {
|
||||
addPolymorphicUnionType(definition) {
|
||||
const types = graphql
|
||||
.parse(definition)
|
||||
.definitions.filter(
|
||||
def => def.kind === 'ObjectTypeDefinition' && def.name.value !== 'Query'
|
||||
)
|
||||
.definitions.filter(def => def.kind === 'ObjectTypeDefinition' && def.name.value !== 'Query')
|
||||
.map(def => def.name.value);
|
||||
|
||||
if (types.length > 0) {
|
||||
@ -250,7 +243,7 @@ module.exports = {
|
||||
|
||||
const inputs = `
|
||||
input ${inputName} {
|
||||
|
||||
|
||||
${Object.keys(model.attributes)
|
||||
.map(attributeName => {
|
||||
return `${attributeName}: ${this.convertType({
|
||||
@ -278,6 +271,7 @@ module.exports = {
|
||||
.join('\n')}
|
||||
}
|
||||
`;
|
||||
|
||||
return inputs;
|
||||
},
|
||||
|
||||
|
||||
@ -12,12 +12,7 @@ const DynamicZoneScalar = require('../types/dynamiczoneScalar');
|
||||
|
||||
const { formatModelConnectionsGQL } = require('./build-aggregation');
|
||||
const types = require('./type-builder');
|
||||
const {
|
||||
mergeSchemas,
|
||||
convertToParams,
|
||||
convertToQuery,
|
||||
amountLimiting,
|
||||
} = require('./utils');
|
||||
const { mergeSchemas, convertToParams, convertToQuery, amountLimiting } = require('./utils');
|
||||
const { toSDL, getTypeDescription } = require('./schema-definitions');
|
||||
const { toSingular, toPlural } = require('./naming');
|
||||
const { buildQuery, buildMutation } = require('./resolvers-builder');
|
||||
@ -60,10 +55,10 @@ const buildTypeDefObj = model => {
|
||||
// Change field definition for collection relations
|
||||
associations
|
||||
.filter(association => association.type === 'collection')
|
||||
.filter(association => attributes[association.alias].private !== true)
|
||||
.forEach(association => {
|
||||
typeDef[
|
||||
`${association.alias}(sort: String, limit: Int, start: Int, where: JSON)`
|
||||
] = typeDef[association.alias];
|
||||
typeDef[`${association.alias}(sort: String, limit: Int, start: Int, where: JSON)`] =
|
||||
typeDef[association.alias];
|
||||
|
||||
delete typeDef[association.alias];
|
||||
});
|
||||
@ -90,9 +85,7 @@ const generateDynamicZoneDefinitions = (attributes, globalId, schema) => {
|
||||
.forEach(attribute => {
|
||||
const { components } = attributes[attribute];
|
||||
|
||||
const typeName = `${globalId}${_.upperFirst(
|
||||
_.camelCase(attribute)
|
||||
)}DynamicZone`;
|
||||
const typeName = `${globalId}${_.upperFirst(_.camelCase(attribute))}DynamicZone`;
|
||||
|
||||
if (components.length === 0) {
|
||||
// Create dummy type because graphql doesn't support empty ones
|
||||
@ -111,9 +104,7 @@ const generateDynamicZoneDefinitions = (attributes, globalId, schema) => {
|
||||
return compo.globalId;
|
||||
});
|
||||
|
||||
const unionType = `union ${typeName} = ${componentsTypeNames.join(
|
||||
' | '
|
||||
)}`;
|
||||
const unionType = `union ${typeName} = ${componentsTypeNames.join(' | ')}`;
|
||||
|
||||
schema.definition += `\n${unionType}\n`;
|
||||
}
|
||||
@ -137,8 +128,7 @@ const generateDynamicZoneDefinitions = (attributes, globalId, schema) => {
|
||||
};
|
||||
|
||||
const buildAssocResolvers = model => {
|
||||
const contentManager =
|
||||
strapi.plugins['content-manager'].services['contentmanager'];
|
||||
const contentManager = strapi.plugins['content-manager'].services['contentmanager'];
|
||||
|
||||
const { primaryKey, associations = [] } = model;
|
||||
|
||||
@ -194,8 +184,7 @@ const buildAssocResolvers = model => {
|
||||
};
|
||||
|
||||
if (
|
||||
((association.nature === 'manyToMany' &&
|
||||
association.dominant) ||
|
||||
((association.nature === 'manyToMany' && association.dominant) ||
|
||||
association.nature === 'manyWay') &&
|
||||
_.has(obj, association.alias) // if populated
|
||||
) {
|
||||
@ -203,31 +192,21 @@ const buildAssocResolvers = model => {
|
||||
queryOpts,
|
||||
['query', targetModel.primaryKey],
|
||||
obj[association.alias]
|
||||
? obj[association.alias]
|
||||
.map(val => val[targetModel.primaryKey] || val)
|
||||
.sort()
|
||||
? obj[association.alias].map(val => val[targetModel.primaryKey] || val).sort()
|
||||
: []
|
||||
);
|
||||
} else {
|
||||
_.set(
|
||||
queryOpts,
|
||||
['query', association.via],
|
||||
obj[targetModel.primaryKey]
|
||||
);
|
||||
_.set(queryOpts, ['query', association.via], obj[targetModel.primaryKey]);
|
||||
}
|
||||
}
|
||||
|
||||
return association.model
|
||||
? strapi.plugins.graphql.services['data-loaders'].loaders[
|
||||
targetModel.uid
|
||||
].load({
|
||||
? strapi.plugins.graphql.services['data-loaders'].loaders[targetModel.uid].load({
|
||||
params,
|
||||
options: queryOpts,
|
||||
single: true,
|
||||
})
|
||||
: strapi.plugins.graphql.services['data-loaders'].loaders[
|
||||
targetModel.uid
|
||||
].load({
|
||||
: strapi.plugins.graphql.services['data-loaders'].loaders[targetModel.uid].load({
|
||||
options: queryOpts,
|
||||
association,
|
||||
});
|
||||
@ -308,9 +287,7 @@ const buildSingleType = model => {
|
||||
|
||||
const singularName = toSingular(modelName);
|
||||
|
||||
const _schema = _.cloneDeep(
|
||||
_.get(strapi.plugins, 'graphql.config._schema.graphql', {})
|
||||
);
|
||||
const _schema = _.cloneDeep(_.get(strapi.plugins, 'graphql.config._schema.graphql', {}));
|
||||
|
||||
const globalType = _.get(_schema, ['type', model.globalId], {});
|
||||
|
||||
@ -357,9 +334,7 @@ const buildCollectionType = model => {
|
||||
const singularName = toSingular(modelName);
|
||||
const pluralName = toPlural(modelName);
|
||||
|
||||
const _schema = _.cloneDeep(
|
||||
_.get(strapi.plugins, 'graphql.config._schema.graphql', {})
|
||||
);
|
||||
const _schema = _.cloneDeep(_.get(strapi.plugins, 'graphql.config._schema.graphql', {}));
|
||||
|
||||
const globalType = _.get(_schema, ['type', model.globalId], {});
|
||||
|
||||
|
||||
@ -44,6 +44,41 @@ const labelModel = {
|
||||
collectionName: '',
|
||||
};
|
||||
|
||||
const carModel = {
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
connection: 'default',
|
||||
name: 'car',
|
||||
description: '',
|
||||
collectionName: '',
|
||||
};
|
||||
|
||||
const personModel = {
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'text',
|
||||
},
|
||||
privateName: {
|
||||
type: 'text',
|
||||
private: true,
|
||||
},
|
||||
privateCars: {
|
||||
nature: 'oneToMany',
|
||||
target: 'application::car.car',
|
||||
dominant: false,
|
||||
targetAttribute: 'person',
|
||||
private: true,
|
||||
},
|
||||
},
|
||||
connection: 'default',
|
||||
name: 'person',
|
||||
description: '',
|
||||
collectionName: '',
|
||||
};
|
||||
|
||||
describe('Test Graphql Relations API End to End', () => {
|
||||
beforeAll(async () => {
|
||||
const token = await registerAndLogin();
|
||||
@ -59,15 +94,17 @@ describe('Test Graphql Relations API End to End', () => {
|
||||
|
||||
modelsUtils = createModelsUtils({ rq });
|
||||
|
||||
await modelsUtils.createContentTypes([documentModel, labelModel]);
|
||||
await modelsUtils.createContentTypes([documentModel, labelModel, carModel, personModel]);
|
||||
}, 60000);
|
||||
|
||||
afterAll(() => modelsUtils.deleteContentTypes(['document', 'label']), 60000);
|
||||
afterAll(() => modelsUtils.deleteContentTypes(['document', 'label', 'car', 'person']), 60000);
|
||||
|
||||
describe('Test relations features', () => {
|
||||
let data = {
|
||||
labels: [],
|
||||
documents: [],
|
||||
people: [],
|
||||
cars: [],
|
||||
};
|
||||
const labelsPayload = [{ name: 'label 1' }, { name: 'label 2' }];
|
||||
const documentsPayload = [{ name: 'document 1' }, { name: 'document 2' }];
|
||||
@ -127,49 +164,46 @@ describe('Test Graphql Relations API End to End', () => {
|
||||
data.labels = res.body.data.labels;
|
||||
});
|
||||
|
||||
test.each(documentsPayload)(
|
||||
'Create document linked to every labels %o',
|
||||
async document => {
|
||||
const res = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
mutation createDocument($input: createDocumentInput) {
|
||||
createDocument(input: $input) {
|
||||
document {
|
||||
test.each(documentsPayload)('Create document linked to every labels %o', async document => {
|
||||
const res = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
mutation createDocument($input: createDocumentInput) {
|
||||
createDocument(input: $input) {
|
||||
document {
|
||||
name
|
||||
labels {
|
||||
id
|
||||
name
|
||||
labels {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
data: {
|
||||
...document,
|
||||
labels: data.labels.map(t => t.id),
|
||||
},
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
data: {
|
||||
...document,
|
||||
labels: data.labels.map(t => t.id),
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { body } = res;
|
||||
const { body } = res;
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
data: {
|
||||
createDocument: {
|
||||
document: {
|
||||
...selectFields(document),
|
||||
labels: expect.arrayContaining(data.labels.map(selectFields)),
|
||||
},
|
||||
expect(body).toMatchObject({
|
||||
data: {
|
||||
createDocument: {
|
||||
document: {
|
||||
...selectFields(document),
|
||||
labels: expect.arrayContaining(data.labels.map(selectFields)),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('List documents with labels', async () => {
|
||||
const res = await graphqlQuery({
|
||||
@ -229,9 +263,7 @@ describe('Test Graphql Relations API End to End', () => {
|
||||
labels: expect.arrayContaining(
|
||||
data.labels.map(label => ({
|
||||
...selectFields(label),
|
||||
documents: expect.arrayContaining(
|
||||
data.documents.map(selectFields)
|
||||
),
|
||||
documents: expect.arrayContaining(data.documents.map(selectFields)),
|
||||
}))
|
||||
),
|
||||
},
|
||||
@ -405,5 +437,184 @@ describe('Test Graphql Relations API End to End', () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('Create person', async () => {
|
||||
const person = {
|
||||
name: 'Chuck Norris',
|
||||
privateName: 'Jean-Eude',
|
||||
};
|
||||
const res = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
mutation createPerson($input: createPersonInput) {
|
||||
createPerson(input: $input) {
|
||||
person {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
data: person,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual({
|
||||
data: {
|
||||
createPerson: {
|
||||
person: {
|
||||
id: expect.anything(),
|
||||
name: person.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
data.people.push(res.body.data.createPerson.person);
|
||||
});
|
||||
|
||||
test("Can't list a private field", async () => {
|
||||
const res = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
{
|
||||
people {
|
||||
name
|
||||
privateName
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Cannot query field "privateName" on type "Person".',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('Create a car linked to a person (oneToMany)', async () => {
|
||||
const car = {
|
||||
name: 'Peugeot 508',
|
||||
person: data.people[0].id,
|
||||
};
|
||||
const res = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
mutation createCar($input: createCarInput) {
|
||||
createCar(input: $input) {
|
||||
car {
|
||||
id
|
||||
name
|
||||
person {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
data: {
|
||||
...car,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toMatchObject({
|
||||
data: {
|
||||
createCar: {
|
||||
car: {
|
||||
id: expect.anything(),
|
||||
name: car.name,
|
||||
person: data.people[0],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
data.cars.push({ id: res.body.data.createCar.car.id });
|
||||
});
|
||||
|
||||
test("Can't list a private oneToMany relation", async () => {
|
||||
const res = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
{
|
||||
people {
|
||||
name
|
||||
privateCars
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Cannot query field "privateCars" on type "Person".',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('Edit person/cars relations removes correctly a car', async () => {
|
||||
const newPerson = {
|
||||
name: 'Check Norris Junior',
|
||||
privateCars: [],
|
||||
};
|
||||
|
||||
const mutationRes = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
mutation updatePerson($input: updatePersonInput) {
|
||||
updatePerson(input: $input) {
|
||||
person {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
where: {
|
||||
id: data.people[0].id,
|
||||
},
|
||||
data: {
|
||||
...newPerson,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(mutationRes.statusCode).toBe(200);
|
||||
|
||||
const queryRes = await graphqlQuery({
|
||||
query: /* GraphQL */ `
|
||||
query($id: ID!) {
|
||||
car(id: $id) {
|
||||
person {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: data.cars[0].id,
|
||||
},
|
||||
});
|
||||
expect(queryRes.statusCode).toBe(200);
|
||||
expect(queryRes.body).toEqual({
|
||||
data: {
|
||||
car: {
|
||||
person: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user