Как я могу псевдоним конкретных запросов GraphQL в Cypress? - PullRequest
0 голосов
/ 17 декабря 2018

В Cypress хорошо задокументировано , что вы можете использовать псевдоним для определенных сетевых запросов, которые затем можно "подождать".Это особенно полезно, если вы хотите что-то сделать в Cypress после того, как определенный сетевой запрос был запущен и завершен.

Пример ниже из документации Cypress:

cy.server()
cy.route('POST', '**/users').as('postUser') // ALIASING OCCURS HERE
cy.visit('/users')
cy.get('#first-name').type('Julius{enter}')
cy.wait('@postUser')

Однако, поскольку я использую GraphQL в своем приложении, псевдонимы больше не становятся простым делом.Это связано с тем, что все запросы GraphQL совместно используют одну конечную точку /graphql.

Несмотря на то, что невозможно провести различие между различными запросами graphQL, используя только конечную точку url, * возможно дифференцировать запросы graphQL с использованиемoperationName (см. Следующее изображение).

enter image description here

Перекопав документацию, похоже, нет пути к псевдониму конечных точек graphQLиспользуя operationName из тела запроса.Я также возвращаю operationName (желтая стрелка) в качестве пользовательского свойства в заголовке моего ответа;однако мне так и не удалось найти способ использовать его для псевдонимов определенных запросов graphQL.

МЕТОД СБОРА 1: Этот метод пытается использовать фиолетовую стрелку, показанную на изображении.

cy.server();
cy.route({
    method: 'POST',
    url: '/graphql',
    onResponse(reqObj) {
        if (reqObj.request.body.operationName === 'editIpo') {
            cy.wrap('editIpo').as('graphqlEditIpo');
        }
    },
});
cy.wait('@graphqlEditIpo');

Этот метод не работает, поскольку псевдоним graphqlEditIpo регистрируется во время выполнения, и поэтому я получаю следующую ошибку:

CypressError: cy.wait() не удалось найти зарегистрированный псевдоним для: '@graphqlEditIpo'.Доступные псевдонимы: 'ipoInitial, graphql'.

МЕТОД СБОРА 2: Этот метод пытается использовать желтую стрелку, показанную на изображении.

cy.server();
cy.route({
    method: 'POST',
    url: '/graphql',
    headers: {
        'operation-name': 'editIpo',
    },
}).as('graphql');
cy.wait('graphql');

Этот метод не работает, потому что свойство headers в объекте параметров для cy.route фактически предназначено для приема заголовков ответов для маршрутов с заглушками в соответствии с документами .Здесь я пытаюсь использовать его для идентификации моего конкретного запроса graphQL, который, очевидно, не будет работать.

Что приводит меня к моему вопросу: как я могу использовать псевдонимы определенных запросов / мутаций graphQL в Cypress?Я что-то пропустил?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Поскольку у меня возникла та же проблема, и я не нашел реального решения этой проблемы, я объединил разные варианты и создал обходной путь, который решает мою проблему.Надеюсь, это может помочь и кому-то еще.

Я на самом деле не «жду», когда запрос будет выполнен, но я перехватываю их все, основываясь на **/graphql url и сопоставляя имя операции в запросе.При совпадении будет выполняться функция с данными в качестве параметра.В этой функции можно определить тесты.

graphQLResponse.js

export const onGraphQLResponse = (resolvers, args) => {
    resolvers.forEach((n) => {
        const operationName = Object.keys(n).shift();
        const nextFn = n[operationName];

        if (args.request.body.operationName === operationName) {
            handleGraphQLResponse(nextFn)(args.response)(operationName);
        }
    });
};

const handleGraphQLResponse = (next) => {
    return (response) => {

        const responseBody = Cypress._.get(response, "body");

        return async (alias) => {
            await Cypress.Blob.blobToBase64String(responseBody)
                .then((blobResponse) => atob(blobResponse))
                .then((jsonString) => JSON.parse(jsonString))
                .then((jsonResponse) => {
                    Cypress.log({
                        name: "wait blob",
                        displayName: `Wait ${alias}`,
                        consoleProps: () => {
                            return jsonResponse.data;
                        }
                    }).end();

                    return jsonResponse.data;
                })
                .then((data) => {
                    next(data);
                });
        };
    };
};

В файле теста

Bindмассив с объектами, где ключом является имя операции, а значением является функция разрешения.

import { onGraphQLResponse } from "./util/graphQLResponse";

describe("Foo and Bar", function() {
    it("Should be able to test GraphQL response data", () => {
        cy.server();

        cy.route({
            method: "POST",
            url: "**/graphql",
            onResponse: onGraphQLResponse.bind(null, [
                {"some operationName": testResponse},
                {"some other operationName": testOtherResponse}
            ])
        }).as("graphql");

        cy.visit("");

        function testResponse(result) {
            const foo = result.foo;
            expect(foo.label).to.equal("Foo label");
        }

        function testOtherResponse(result) {
            const bar = result.bar;
            expect(bar.label).to.equal("Bar label");
        }
    });
}

Кредиты

Использовал команду blob из glebbahmutov.ком

0 голосов
/ 18 марта 2019

Это работает для меня!

Cypress.Commands.add('waitForGraph', operationName => {
  const GRAPH_URL = '/api/v2/graph/';
  cy.route('POST', GRAPH_URL).as("graphqlRequest");
  //This will capture every request
  cy.wait('@graphqlRequest').then(({ request }) => {
    // If the captured request doesn't match the operation name of your query
    // it will wait again for the next one until it gets matched.
    if (request.body.operationName !== operationName) {
      return cy.waitForGraph(operationName)
    }
  })
})

Просто не забудьте написать свои запросы с уникальными именами как возможные, потому что имя операции зависит от него.

0 голосов
/ 20 декабря 2018

Если «ожидание», а не «алиасинг» само по себе является основной целью, то, как я до сих пор сталкивался, самый простой способ сделать это - наложить псевдоним на общие запросы graphql, а затем сделать рекурсивный вызов функции для 'подождите 'таргетинга на вновь созданный псевдоним, пока не найдете конкретную операцию graphql, которую вы искалинапример,

Cypress.Commands.add('waitFor', operationName => {
  cy.wait('@graphqlRequest').then(({ request }) => {
    if (request.body.operationName !== operationName) {
      return cy.waitFor(operationName)
    }
  })
})

Это, конечно, имеет свои оговорки и может или не может работать в вашем контексте.Но это работает для нас.

Я надеюсь, что Cypress сделает это менее хакерским способом в будущем.

PS.Я хочу отдать должное тому, откуда я получил это вдохновение, но, похоже, оно потеряно в киберпространстве.

...