Как дождаться установки файла cookie?

Я пишу приемочные тесты для функции входа в мое приложение. В какой-то момент я хочу перепроверить срок действия файла cookie.

При нажатии на кнопку «Войти» на мой сервер отправляется запрос graphql, который отвечает Jwt. После получения jwt приложение устанавливает файл cookie с

document.cookie = ...

В моем тесте Cypress я проверяю токен следующим образом:

Then("sa session s'ouvre pour {SessionDurationType}", expectedDuration => {
  cy.get('@graphql').then(() => {
    cy.wait(1000)
    cy.getCookie('token').then(cookie => {
      const tokenDuration = getTokenDuration(cookie.value)
     expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
    })
  })
})

С cy.get('@graphql') я жду, пока запрос graphql вернет ответ. Псевдоним определяется следующим образом:

cy.stub(win, 'fetch', fetch).as('graphql')

При получении приложение устанавливает куки.

Моя проблема в том, что мне не нравится следующий вызов:

cy.wait(1000)

Без этого вызова я всегда получаю неопределенный файл cookie.

Есть ли способ получить этот файл cookie в течение некоторого времени, которое может быть намного меньше 1000 мс? Я пробовал много вещей, но безуспешно...

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
6 034
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы должны написать рекурсивную функцию обещания, попробуйте следующее

function checkCookie() {
  // cy.getCookie returns a thenebale
  return cy.getCookie('token').then(cookie => {
    const tokenDuration = getTokenDuration(cookie.value);
    // it checks the seconds right now, without unnecessary waitings
    if (tokenDuration.asSeconds() !== expectedDuration.asSeconds()) {
      // waits for a fixed milliseconds amount
      cy.wait(100);
      // returns the same function recursively, the next `.then()` will be the checkCookie function itself
      return checkCookie();
    }
    // only when the condition passes returns a resolving promise
    return Promise.resolve(tokenDuration.asSeconds());
  })
}

Then("sa session s'ouvre pour {SessionDurationType}", expectedDuration => {
  cy.get('@graphql').then(() => {
    checkCookie()
      .then(seconds => {
        expect(seconds).to.equal(expectedDuration.asSeconds())
      })
  })
})

Обратите внимание, что функция должна быть улучшена, потому что

  • Я не параметризовал expectedDuration и т. д. (это выходит за рамки показа вам, как это сделать)
  • он ждет вечно без проверки счетчика циклов

Но это работает (я проверил в другом контексте, прежде чем ответить вам), и если у вас есть еще какие-то проблемы, поделитесь «рабочим» репозиторием GitHub, чтобы я мог клонировать и проверить его с вашим собственным решением.

Дайте мне знать, если это недостаточно ясно ?

ОБНОВИТЬ

Мы (меня и Томмазо) написали плагин, который поможет вам с такими проверками, он называется кипарис-подождите-пока.

Пожалуйста, поблагодарите сообщество Суббота с открытым исходным кодом за это, мы разработали его в одну из суббот ?

Основываясь на ответе @NoriSte, я придумал следующий рабочий код:

function awaitNonNullToken(elapsedTimeInMs = 0) {
  let timeDeltaInMs = 10

  if (elapsedTimeInMs > Cypress.env('timeoutInMs')) {
    return Promise.reject(new Error('Awaiting token timeout'))
  }

  return getTokenCookie().then(cookie => {
    if (cookie === null) {
      cy.wait(timeDeltaInMs)
      elapsedTimeInMs += timeDeltaInMs
      return awaitNonNullToken(elapsedTimeInMs)
    }
    return Promise.resolve(cookie.value)
  })
}

Я преобразовал это в класс ES6, который я считаю немного более элегантным:

class TokenHandler {
  constructor () {
    this.TIME_DELTA_IN_MS = Cypress.env('timeDeltaInMs')
    this.TIMEOUT_IN_MS = Cypress.env('timeoutInMs')
    this.elapsedTimeInMs = 0
  }

  getToken () {
    if (this.elapsedTimeInMs > this.TIMEOUT_IN_MS) {
      return Promise.reject(new Error('Awaiting token timeout'))
    }
    return getTokenCookie().then(cookie => {
      if (cookie === null) {
        cy.wait(this.TIME_DELTA_IN_MS)
        this.elapsedTimeInMs += this.TIME_DELTA_IN_MS
        return this.getToken()
      }
      return Promise.resolve(cookie.value)
    })
  }
}

и переработал мой шаг следующим образом:

cy.get('@graphql').then(() => {
  const handler = new TokenHandler
  handler.getToken().then(token => {
    const tokenDuration = getTokenDuration(token)
    expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
  })
})

Это работает отлично, спасибо.

Мне не нравится тайм-аут в этом, я должен сказать, для изменений дома. Я придумал это решение на основе ответа @NoriSte вместе с DomMutation Observers.

   getFileUploadItem().get(".upload-item--state i")
    .should("have.class", "ngx-fileupload-icon--start")
    .then(item => {
        const iconEl = item.get(0);
        const states: string[] = [];

        return new Promise((resolve, reject) => {
          const observer = new MutationObserver((mutations: MutationRecord[]) => {
              const mutationEl = mutations[0].target as HTMLElement;
              const className  = mutationEl.getAttribute("class");

              states.push(className);

              if (className === "ngx-fileupload-icon--uploaded") {
                  resolve(states);
              }
          });

          observer.observe(iconEl, {
              subtree: true,
              attributes: true,
              attributeFilter: ["class"]
          });
        });
    })
    .then((value) => expect(value).to.deep.equal(
      ["ngx-fileupload-icon--progress", "ngx-fileupload-icon--uploaded"])
    );

Другие вопросы по теме