Решено и отклонено promises в пользовательском Jasmine Matcher
История:
Мы разработали индивидуальный набор жасмина, который выполняет две основные функции:
- мышь над определенным элементом
- проверьте, есть ли всплывающая подсказка с нужным текстом
Реализация:
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip");
browser.actions().mouseMove(elm).perform();
browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.");
return {
pass: tooltipPage.tooltip.getText().then(function(actualTooltip) {
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
message: "Element does not have the tooltip '" + expectedTooltip + "'."
};
}
};
},
где tooltipPage
- объект страницы, определенный отдельно:
var Tooltip = function () {
this.tooltip = element(by.css(".tooltip"));
};
module.exports = new Tooltip();
Использование довольно удобно для нас и действительно помогает следовать принципу DRY, сохраняя нашу тестовую базу кода чистой и удобочитаемой:
expect(page.fromDateInput).toHaveTooltip("After");
Проблема и вопрос:
Теперь то, что я пытаюсь сделать, состоит в том, чтобы иметь дескриптор сопряжения 2 варианта использования отдельно:
- нет курсора мыши над отображаемым вообще (что, в принципе, отклонено
browser.wait()
)
- есть всплывающая подсказка, но не желаемая
Как я могу улучшить совпадение, чтобы иметь возможность обрабатывать эти две проблемы отдельно и сообщать о разных ошибках?
Что я пробовал:
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip");
browser.actions().mouseMove(elm).perform();
return browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.").then(function () {
return {
pass: tooltipPage.tooltip.getText().then(function(actualTooltip) {
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
message: "Element does not have the tooltip '" + expectedTooltip + "'."
};
}, function () {
return {
pass: false,
message: "No tooltip shown on mouse over the element"
}
});
}
};
},
Здесь я попытался разрешить browser.wait()
явно и обрабатывать случаи "успеха" и "ошибки" отдельно. Это привело к тайм-ауту Jasmine Spec и огромному "красному" тексту на консоли:
Expected ({ ptor_: ({ setFileDetector: Function, ...
5 minutes scrolling here
... InnerHtml: Function, getId: Function, getRawId: Function }) to have tooltip 'After'.
Боюсь, я не могу вернуть обещание от функции "сравнить".
Ответы
Ответ 1
В соответствии с jasminewd2 (адаптер для Jasmine-to-WebDriverJS. Используется в Protractor) code -
Ожидание разрешает любой promises для действительных и ожидаемых значений, а также свойство pass
объекта result
.
Итак, если вообще есть функция асинхронного вызова или обещание, которое необходимо разрешить в пользовательском совпадении/ожидании, тогда его необходимо обернуть в значение result.pass
, чтобы транспортир ожидал, что обещание будет разрешено.
В этом вопросе встречается ошибка jasmine spec timeout
, поскольку транспортир не может понять, что перед выполнением этой конкретной операции необходимо решить проблему. Чтобы решить эту проблему, либо передайте функцию async в операторе ожидания напрямую, либо передайте ее в значение pass
объекта result
. Здесь код для него -
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip");
browser.actions().mouseMove(elm).perform();
return {
pass: browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.").then(function () {
tooltipPage.tooltip.getText().then(function(actualTooltip) {
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
}, function () {
return false;
}),
message: "Error Occured"
}
}
};
},
Однако проблема с указанным выше кодом заключается в том, что пользовательское сообщение об ошибке не может быть создано. Чтобы решить эту проблему, лучшим методом, который я смог найти, было то, что я должен явно вернуть объект result
, чтобы при необходимости ему можно было присвоить сообщение об ошибке. Вот пример -
var result = {};
result.pass = browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.").then(function () {
tooltipPage.tooltip.getText().then(function(actualTooltip) {
result.message = "Element does not have the tooltip '" + expectedTooltip + "'.";
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
}, function () {
result.message = "No tooltip shown on mouse over the element";
return false;
});
return result;
Примечание. Если в объекте result
нет свойства message
, тогда транспортитор попытается создать общее сообщение об ошибке, и оно будет содержать объект обещания (длительное сообщение, начинающееся с - { ptor_: ... }
), как показано в вопросе.
Надеюсь, что это поможет.
Ответ 2
Ну, я помню, где-то читал, что жасмин 2 не поддерживает тип помощника, который вы пытаетесь сделать (с функцией async внутри) и возвращающий promises.. Я попытаюсь найти источник и обновить его здесь. Кроме того, вы не должны делать действия мыши внутри соединителя, это не точка соответствия.
Итак, в основном, что я говорю и предлагаю следующее:
Если вы хотите получить чистый код, экспортируйте его в функцию и вызовите ее.
var checkToolTipVisibility (elm, expectedTooltip) {
browser.actions().mouseMove(elm).perform();
browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.");//optional then here if you want to fail with a timeout or something...
expect(tooltipPage.tooltip.getText()).toEqual(expectedTooltip);
}
checkToolTipVisibility(page.fromDateInput, "After");//usage
Я думаю, что это очень чистое и простое решение, которое не требует каких-либо пользовательских совпадений, и это способ жасмина делать вещи (а не функции async в состязаниях), что я использую в своем коде, кроме тех, функции находятся в файле utils.js, который я требую при необходимости.
Надеюсь, я помог, и я продолжу искать источник моего первого заявления!
Ответ 3
Основываясь на @Girish Sortur идеальном ответе, вот полный код матчи, который теперь отлично работает как с отсутствующей подсказкой, так и с различными текстовыми случаями всплывающей подсказки отдельно
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip"),
result = {};
// mouse over the element
browser.actions().mouseMove(elm).perform();
// wait for tooltip to appear and handle errors
result.pass = browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000).then(function () {
return tooltipPage.tooltip.getText().then(function(actualTooltip) {
result.message = "Expected tooltip: '" + expectedTooltip + "'. Actual tooltip: '" + actualTooltip + "'.";
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
})
}, function () {
result.message = "No tooltip shown on mouse over the element";
return false;
});
return result;
}
};
},