ProtractorJS_условия if/else if/else не работают с методом isPresent()?

protractor
selenium
uiautomator
testing
protractorjs
Теги: #<Tag:0x00007f3d4639e218> #<Tag:0x00007f3d46393a20> #<Tag:0x00007f3d46392f80> #<Tag:0x00007f3d46392b70> #<Tag:0x00007f3d46392508>

(Алексей Щербин) #1

Доброго времени суток!

Я стремительно стараюсь осваивать инструмент ProtractorJS, но постоянно возникают проблемы. Может я чего не понимаю ,не спорю. Мне еще многому следует обучиться. И так, возникла проблема что не отрабатывают условия в моем коде. Тест идет на страницу с таблицей и там есть много строк с значением Processed. Но порой в следствии действия других тестов, появляются значения Client, Awaiting, Call. И вот мой код должен их находить, и если нашел - идти дальше по сценарию. Но он стопорится на первом условии (первое условие выдает false, так как я знаю что этого элемента нет в таблице) и тест падает, не пробегая дальше по условиям (в тестируемой таблице есть значение Awaiting).

main_page.button().click();

browser.wait(ExpectedConditions.visibilityOf(element(by.cssContainingText('.grid-cols-3', 'Processed'))), 10000);
if (element(by.cssContainingText('.grid-cols-3', 'Client')).isPresent()) {

element(by.cssContainingText('.grid-cols-3', 'Client')).click().then(function() {
	element(by.css('#FinApplication')).click();
});

} else if (element(by.cssContainingText('.grid-cols-3', 'Awaiting')).isPresent()) {

element(by.cssContainingText('.grid-cols-3', 'Awaiting')).click().then(function() {
	element(by.css('#FinApplication')).click();
});

} else if (element(by.cssContainingText('.grid-cols-3', 'Call')).isPresent()) {

element(by.cssContainingText('.grid-cols-3', 'Call')).click().then(function() {
	element(by.css('#FinApplication')).click();
});

} else {

browser.getAllWindowHandles().then(function(handles) {
	browser.driver.close();
	browser.switchTo().window(handles[0]);
});

};

Помогите, пожалуйста. Вроде же все правильно делаю. Метод IsPresent возвращает promise true/false, следовательно отдельно писать ==true по идее не надо, так как if/else if выполняется если условие выдает true, если не указано противоположного. Самое странное, что вчера этот код работал о_О

Webdriver-manager 12.0.6
Protractor 5.1.1
Jasmine 2.6.0
NodeJS 7.8.0


(Valentin Buryakov) #2

Вот это плохо конечно, нужно избегать зависимых тестов. И не понятно, зачем вы ищете эти значения.
А так проблема в том, что IsPresent возвращается не true/false, а Promise, в который и завернуто булевое значение. Сам Promise в if интерпретируется как true и поэтому оно всегда будет заходить внутрь if'a
Вам нужно делать так, но это всё равно не очень красивое решение, может получиться большая вложенность и как следствие нечитаемость кода

element(by.cssContainingText('.grid-cols-3', 'Call')).isPresent().then(function(present) {
    if (present) then 
           // ваш код
});

И вообще посмотрите в сторону перехода на ES6 или TypeScript, на ES5 (как у вас) щас никто не пишет. Современные фичи JS'a значительно упрощают жизнь + типизация, а также работа с асинхронностью через async/await.


(Алексей Щербин) #3

У меня в продукте все процессы зависимы друг от друга. Нет возможности чистить БД перед тестом. Вручную каждый раз лезть и чистить мне надоело и я написал скрипт, который перед определенным тестом выполняет заданную последовательность действий по зачистке.

Теперь понял. Благодарю

Предложенный Вами вариант я знаю, использовал кое-где. Но Вы правы, у меня 4 условия, и если их впихнуть таким образом - получится крайне не читабельно. Но выхода, увы, не вижу. Разве что разбить на if/else каждое условие, где в else ничего не делать.

А вот отдельная благодарность. Хотя я и не ощущаю каких-либо трудностей при написании, но нужно ж быть в тренде технологий :slight_smile:


(vmaximv) #4

Даже в случае депендов - ветвления в тестах явно указывает, что вы делаете что-то не так. Вы должны полностью контролировать поведение AUT - иначе это не тесты, а "ad hoc" либо попытка изобрести AI.


(Алексей Щербин) #5

Я весьма зеленый в автоматизации. Оптимизирую по ходу дела. У меня вначале вовсе было два теста по 500 строк, в котором шел долгий процесс. Было достаточно удобно, по правде говоря (во всяком случае на этапе построения хэппи-пасса всего процесса). Но потом протрактор начал сбоить и таки пришлось все разделить. И тем не менее есть тесты по 200 строк. Они выполняют проверку определенного элемента. И обьемность зачастую обусловлена тем, что продукт построен со своими приколами, где лоадер сделан скриптом и повешен поверх ангуляра (да простят меня за такое обьяснение). Приходится почти перед каждым шагом ставить вейты (ранее ставил слипы, но понял что это гиблое дело). Местами ставил ignoreSynchronization=true, потом false. В итоге дошел сегодня до того, что если запускать внешний скрипт в тесте в начале (ну например как я для зачистки БД _возможно надо его вывести вовсе наружу для запуска), то протрактор сначала бежит по всему тесту и принимает значение ignoreSynchronization последнее, и плевать что там указано во внешнем скрипте.

Я постарался сделать скрипт универсальным, так как тесты могут упасть исходя из предназначения тестов, в разных местах, и создадутся записи, которые будут блокировать дальнейший ход тестов, как и их повторная прогонка. Если бы Вы видели мой продукт и были с ним знакомы, то, я думаю, Вы бы меня поняли :wink:

Вот подумываю сделать единый файл с тест-датой по всем тестам, так как как я и писал, нет возможности чистить БД. Сейчас тестов не много, и все хэппи-пасс. А когда разрастутся, то будет сложно лазать по всем и править, даже учитывая что я всегда создаю переменные перед тест-степами.


(Valentin Buryakov) #6

Вот можете попробовать такое, ожидаем сразу все промисы, а потом смотрим, если какой-то true, то кликаем

protractor.promise.all([
         element(by.cssContainingText('.grid-cols-3', 'Client')).isPresent(),
         element(by.cssContainingText('.grid-cols-3', 'Awaiting')).isPresent(),
         element(by.cssContainingText('.grid-cols-3', 'Call')).isPresent()
    ]).then(function (arr) {
      if (arr.indexOf(true) >= 0) {
             element(by.css('#FinApplication')).click();
        }
    });

(vmaximv) #7

Это сугубо ваши проблемы, не стоило доводить до такого. KISS.


(Алексей Щербин) #8

Идея понятно. Благодарю за предложение. Но Вы не учли то, что при наличии элемента, мне по нему необходимо сначала кликнуть, а потом уже кликнуть по элементу element(by.css('#FinApplication')) :frowning: А Ваш код да, шикарен, возьму на заметку


(Алексей Щербин) #9

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

		element(by.cssContainingText('.grid-cols-3', 'Client input')).isPresent().then(function(result) {
			if (result == true) {
				element(by.cssContainingText('.grid-cols-3', 'Client input')).click().then(function() {
					element(by.css('#FinApplicationDetail')).click();
                                });

				browser.getAllWindowHandles().then(function(handles) {
					browser.driver.close();
					browser.switchTo().window(handles[0]);
				});
			} else {};
		});

		element(by.cssContainingText('.grid-cols-3', 'Awaiting')).isPresent().then(function(result) {
			if (result == true) {
				element(by.cssContainingText('.grid-cols-3', 'Awaiting')).click().then(function() {
					element(by.css('#FinApplicationDetail')).click();
				});

				browser.getAllWindowHandles().then(function(handles) {
					browser.driver.close();
					browser.switchTo().window(handles[0]);
				});
			} else {};
		});

		element(by.cssContainingText('.grid-cols-3', 'Call')).isPresent().then(function(result) {
			if (result == true) {
				element(by.cssContainingText('.grid-cols-3', 'Call')).click().then(function() {
					element(by.css('#FinApplicationDetail')).click();
				});
				
				browser.getAllWindowHandles().then(function(handles) {
					browser.driver.close();
					browser.switchTo().window(handles[0]);
				});
			} else {};
		});
	
		browser.getAllWindowHandles().then(function(handles) {
			browser.driver.close();
			browser.switchTo().window(handles[0]);
		});

(Oleksandr Khotemskyi) #10

Набросал свой вариант решения проблемы. Я не вижу цикла в вашем коде, как вы отрабатываете ситуацию если много одинаковых статусов?

// Сюда в массив добавляйте новые статусы для обработки если они появятся.
const VALUES_TO_HANDLE = ['Awaiting', 'Client input']

$$('.grid-cols-3').filter(valueElem => {
    return valueElem.getText().then(text=> VALUES_TO_HANDLE.includes(text))
}).map(elem => {
    elem.click()
    $('#FinApplicationDetail').click()
    browser.getAllWindowHandles().then(handles=> {
        browser.driver.close()
        browser.switchTo().window(handles[0])
    })
})

(Алексей Щербин) #11

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

Мне цикл не требуется. В моем продукте не могут быть указанных статусов более 1 шт. В таблице может быть только один из них в кол-ве 1 шт. Если это не так - это уже ошибка продукта. Но Ваш код взял на заметку, благодарю!