Я пытаюсь использовать cypress-wait-until
для простого случая. https://github.com/NoriSte/cypress-wait-until
Рабочий код (кипарис-ждите-пока не используется)
before(() => {
cy.visit('http://localhost:8080/en/registration');
});
describe('Foo', () => {
it('should check that registration button is displayed', () => {
const selector = 'button[data-test=startRegistration-individual-button]';
cy.get(selector).should('exist');
});
});
Не работает, время повторной попытки истекло
before(() => {
cy.visit('http://localhost:8080/en/registration');
});
describe('Foo', () => {
it('should check that registration button is displayed', () => {
const options = { timeout: 8000, interval: 4000 };
const selector = 'button[data-test=startRegistration-individual-button]';
cy.waitUntil(() => cy.reload().then(() => Cypress.$(selector).length), options);
cy.get(selector).should('exist');
});
});
Не работает, см. ошибку ниже
before(() => {
cy.visit('http://localhost:8080/en/registration');
});
describe('Foo', () => {
it('should check that registration button is displayed', () => {
const options = { timeout: 8000, interval: 4000 };
const selector = 'button[data-test=startRegistration-individual-button]';
cy.waitUntil(() => {
cy.reload();
return Cypress.$(selector).length;
}, options);
cy.get(selector).should('exist');
});
Для двух версий не работает, как только я удаляю cy.reload()
, он начинает работать.
Что я могу сделать, чтобы он работал с перезагрузкой?
Эта команда, которую я написал, работает правильно.
Cypress.Commands.add('refreshUntil', (selector: string, opts?: { retries: number; waitAfterRefresh: number }) => {
const defaultOptions = {
retries: 10,
waitAfterRefresh: 2500,
};
const options = { ...defaultOptions, ...opts };
function check(selector: string): any {
if (Cypress.$(selector).length) { // Element is there
return true;
}
if (options.retries === 0) {
throw Error(`${selector} not found`);
}
options.retries -= 1;
cy.log(`Element ${selector} not found. Remaining attempts: ${options.retries}`);
cy.reload();
// Wait a some time for the server to respond
return cy.wait(options.waitAfterRefresh).then(() => check(selector));
}
check(parsedSelector);
});
Я мог видеть две разности потенциалов с waitUntil
от cypress-wait-until
Cypress.$(selector).length
будет новым при каждой попыткеwait
время, прежде чем снова проверить, есть ли элемент.Вот рабочее решение с использованием cypress-wait-until
cy.waitUntil(() => cy.reload().wait(2500).then(() => Cypress.$(selector).length), options);
Я думаю, моя проблема в том, что страница загружается долго, а элемент, который я хочу проверить, не отображается сразу
Похоже, ваш тест очень недетерминирован. Почему вам нужно перезагрузить, если элемент не отображается? Появляется ли он в конце концов, если вы ждете достаточно долго без перезагрузки?
Первоначальная загрузка приложения может занять ~5 секунд, затем отображается таблица с элементами из базы данных. Если элемент уже есть в базе данных, он будет отображаться, иначе нет. Затем мне нужно обновить страницу и дождаться повторной загрузки данных, прежде чем проверять, есть ли они. и т.д.
Я детерминирован, чтобы добраться до сути - можете ли вы заглушить вызов API, чтобы издеваться над базой данных?
По крайней мере, формат cy.waitUntil()
выглядит нормально — предположим, что ошибка только для последнего неработающего блока кода?
Это правильно, только пример дает ошибку. Я также отредактирую свой вопрос, поскольку я написал свою собственную функцию, которая работает для меня.
@A.A.Qadosh, нашел... Ключом было ожидание после перезагрузки. Спасибо
Вот рабочее решение с использованием кипарисового ожидания
cy.waitUntil(() => cy.reload().wait(2500).then(() => Cypress.$(selector).length), options);
Правила Cypress применяются как внутри cy.waitUntil()
, так и снаружи, поэтому .wait(2500)
было бы плохой практикой.
Было бы лучше изменить вашу неповторную команду Cypress.$(selector).length
на правильную команду повторной попытки Cypress. Таким образом, вы получаете 4 секунды (по умолчанию) на повторную попытку, но ждете столько, сколько необходимо.
В частности, поскольку cy.waitUntil()
повторяется n раз, вы ждете (тратите впустую) много секунд.
cy.waitUntil(() => { cy.reload(); cy.get(selector) }, options)
// NB retry period for `cy.get()` is > 2.5 seconds
Я не уверен, что то, что вы предлагаете, сработает. diogonunes.com/blog/cypress-tips-tricks/#waits
Если мистер Гекко прав, да, я согласен. Но его пример также указывает на то, что ваш исходный код должен был работать, и по логике .wait(2500)
не должен быть нужен, так как cy.waitUntil()
имеет встроенное ожидание — и имеет опции для тайм-аута и увеличения интервала.
В итоге я написал свой собственный метод (вдохновленный cypress-wait-until
) без необходимости долго ждать.
/**
* Run a check, and then refresh wait until an element is displayed.
* Retries for a specified amount of time.
*
* @function
* @param {function} firstCheckFunction - The function to run before checking if the element is displayed.
* @param {string|{ selector: string, type: string }} selector - The selector to search for. Can be a string or an object with selector and type properties.
* @param {WaitUntilOptions} [opts = {timeout: 5000, interval: 500}] - The options object, with timeout and interval properties.
* @throws {Error} if the firstWaitFunction parameter is not a function.
* @throws {Error} if the specified element is not found after all retries.
* @example
* cy.refreshUntilDisplayed('#element-id', () => {...});
* cy.refreshUntilDisplayed({ selector: 'element-id', type: 'div' }, () => {...});
*/
Cypress.Commands.add('waitFirstRefreshUntilDisplayed', (firstCheckFunction, selector: string | { selector: string, type: string }, opts = {}) => {
if (!(firstCheckFunction instanceof Function)) {
throw new Error(`\`firstCheckFunction\` parameter should be a function. Found: ${firstCheckFunction}`);
}
let parsedSelector = '';
// Define the default options for the underlying `cy.wait` command
const defaultOptions = {
timeout: 5000,
interval: 500,
};
const options = { ...defaultOptions, ...opts };
// Calculate the number of retries to wait for the element to be displayed
let retries = Math.floor(options.timeout / options.interval);
const totalRetries = retries;
if (typeof selector === 'string') {
parsedSelector = selector;
}
if (typeof selector !== 'string' && selector.selector && selector.type) {
parsedSelector = `${selector.type}[data-test=${selector.selector}]`;
}
// Define the check function that will be called recursively until the element is displayed
function check(selector: string): boolean {
if (Cypress.$(selector).length) { // Element exists
return true;
}
if (retries < 1) {
throw Error(`${selector} not found`);
}
if (totalRetries !== retries) { // we don't reload first time
cy.log(`Element ${parsedSelector} not found. ${retries} left`);
cy.reload();
}
// Waits for the firstCheckFunction to return true,
// then pause for the time define in options.interval
// and call recursively the check function
cy.waitUntil(firstCheckFunction, options).then(() => { // We first for firstCheckFunction to be true
cy.wait(options.interval).then(() => { // Then we loop until the selector is displayed
retries -= 1;
return check(selector);
});
});
return false;
}
check(parsedSelector);
});
cypress-wait-until
работает у меня сexample.com
. Тот же обратный вызов, но изменение селектора сh1
(успешно) наh2
(неудачно). Такой ошибки не возникает.