diff --git "a/plugins/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" "b/plugins/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" index c36eee7cb..85c500be1 100644 --- "a/plugins/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" +++ "b/plugins/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/\320\242\320\265\321\201\321\202\320\232\320\273\320\270\320\265\320\275\321\202\321\213/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" @@ -1,1880 +1,1884 @@ -&НаКлиенте -Перем ЗапущенныеТестКлиенты; - -&НаКлиенте -Перем КонтекстЯдра; - -&НаКлиенте -Перем ПортПоУмолчанию; - -&НаКлиенте -Перем НастройкиМодальныхОкон; - -&НаКлиенте -Перем ЗаголовкиМодальныхОкон; - -&НаКлиенте -Перем ПоляМодальныхОкон; - -&НаКлиенте -Перем СписокПропускаемыхФорм; - -&НаКлиенте -Перем КешПроверкиОкон; - -// { Plugin interface -&НаКлиенте -Функция ОписаниеПлагина(КонтекстЯдра, ВозможныеТипыПлагинов) Экспорт - Возврат ОписаниеПлагинаНаСервере(ВозможныеТипыПлагинов); -КонецФункции - -&НаСервере -Функция ОписаниеПлагинаНаСервере(ВозможныеТипыПлагинов) - КонтекстЯдраНаСервере = ВнешниеОбработки.Создать("xddTestRunner"); - Возврат ЭтотОбъектНаСервере().ОписаниеПлагина(КонтекстЯдраНаСервере, ВозможныеТипыПлагинов); -КонецФункции - -&НаКлиенте -Процедура Инициализация(КонтекстЯдраПараметр) Экспорт - КонтекстЯдра = КонтекстЯдраПараметр; - УстановитьНастройкиМодальныхОконПоУмолчанию(); -КонецПроцедуры - -&НаКлиенте -Функция ПортПоУмолчанию() Экспорт - Если Не ЗначениеЗаполнено(ПортПоУмолчанию) Тогда - УстановитьПортПоУмолчанию(49538); - КонецЕсли; - Возврат ПортПоУмолчанию; -КонецФункции - -&НаКлиенте -Процедура УстановитьПортПоУмолчанию(Знач Порт) Экспорт - ПортПоУмолчанию = Порт; -КонецПроцедуры - -&НаКлиенте -Процедура ПодключитьТестКлиент_ПакетныйРежим(Параметры_xddTestClient, ДопПараметры = Неопределено) Экспорт - ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка("ПодключитьТестКлиент: Подключаем тест-клиент пакетный режим")); - - Если ЗначениеЗаполнено(Параметры_xddTestClient) И ТипЗнч(Параметры_xddTestClient[0]) <> Тип("ФиксированныйМассив") - Тогда - НовыйМассивПараметров = Новый Массив; - НовыйМассивПараметров.Добавить(Параметры_xddTestClient); - Параметры_xddTestClient = НовыйМассивПараметров; - КонецЕсли; - - Если Не ЗначениеЗаполнено(ДопПараметры) Тогда - ДопПараметры = ""; - Иначе - ДопПараметры = ДопПараметры[0]; - КонецЕсли; - - Для Каждого ОчередныеПараметры Из Параметры_xddTestClient Цикл - Попытка - ПользовательПарольПорт = РазложитьСтрокуВМассивПодстрок(ОчередныеПараметры[0], ":"); - Если ПользовательПарольПорт.Количество() = 3 Тогда - ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("ПодключитьТестКлиент: параметры %1", - СтрСоединить(ПользовательПарольПорт, ":")))); - - ОписаниеТестКлиента = ПодключитьТестКлиент( - ПользовательПарольПорт[0], - ПользовательПарольПорт[1], - ПользовательПарольПорт[2], - ДопПараметры); - ТестКлиент = ОписаниеТестКлиента.Клиент; - - ЗапомнитьДанныеТестКлиента(ТестКлиент, ПользовательПарольПорт[0], ОписаниеТестКлиента.Порт, - ДопПараметры); - Иначе - ОписаниеТестКлиента = ПодключитьТестКлиент("", "", 0, ДопПараметры); - ТестКлиент = ОписаниеТестКлиента.Клиент; - - ЗапомнитьДанныеТестКлиента(ТестКлиент, "", ОписаниеТестКлиента.Порт, ДопПараметры); - КонецЕсли; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = "Ошибка подключения тест-клиента в пакетном режиме. - |" + ПодробноеПредставлениеОшибки(Инфо); - - ВызватьИсключение ЗаписатьОшибкуВЖурналеРегистрации(КонтекстЯдра.Отладка(ОписаниеОшибки)); - //Сообщить(ОписаниеОшибки, СтатусСообщения.ОченьВажное); // для кого сообщить, если ПакетныйРежим? - КонецПопытки; - КонецЦикла; - -КонецПроцедуры - -// Подключить тест-клиент -// -// Параметры: -// ИмяПользователя - Строка - имя\логин пользователя -// Пароль - Строка - пароль пользователя -// Порт - Число - порт подключения. Порт может быть изменен. -// ДопПараметры - Произвольный - доп.параметры, которые допустимы на клиенте -// -// Возвращаемое значение: -// Структура - описание тест-клиента, если удалось подключить, или Неопределено -// * Клиент - ТестируемоеПриложение, Неопределено - тестовый клиент, если удалось подключиться -// * Порт - Число - порт подключения. Совпадет с переданным, если порт был не занят, и выдается новый, если исходный порт был занят -// -&НаКлиенте -Функция ПодключитьТестКлиент(Знач ИмяПользователя = "", Знач Пароль = "", Знач Порт = 0, Знач ДопПараметры = "") Экспорт - Перем ПодключенныйТестКлиент; - - ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("ПодключитьТестКлиент: - |ИмяПользователя: %1 - |Пароль: %2 - |Порт: %3 - |ДопПараметры: %4", ИмяПользователя, Пароль, Порт, ДопПараметры))); - - Результат = НовоеОписаниеТестКлиента(); - - Порт = ПолучитьПорт(Порт); - Порт = НайтиСвободныйПортЕслиТекущийЗанят(Порт); - - Если Не ЗначениеЗаполнено(СписокПропускаемыхФорм) Тогда - СписокПропускаемыхФорм = Новый СписокЗначений; - КонецЕсли; - КешПроверкиОкон = Новый Соответствие; - - ПодключенныйТестКлиент = Неопределено; - - Попытка - Выполнить "ПодключенныйТестКлиент = Новый ТестируемоеПриложение(, XMLСтрока(Порт));"; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = "Ошибка подключения тест-клиента по порту " + Порт + " - |" + ПодробноеПредставлениеОшибки(Инфо); - - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); - КонтекстЯдра.Отладка("ПодключитьТестКлиент: ОШИБКА: - | "+ОписаниеОшибки); - - ПодключенныйТестКлиент = Неопределено; - КонецПопытки; - - Если ПодключенныйТестКлиент = Неопределено Тогда - ВызватьИсключение КонтекстЯдра.Отладка("Не удалось создать объект ТестируемоеПриложение. - |Возможно, что 1С:Предприятие 8 не было запущено в режиме Менеджера тестирования (ключ командной строки /TESTMANAGER) - |При запуске Предприятия через Конфигуратор можно включить этот режим в параметрах конфигуратора Сервис -> Параметры -> Запуск 1С:Предприятия -> Дополнительные -> Автоматизированное тестирование -> пункт ""Запускать как менеджер тестирования""."); - КонецЕсли; - - // Попытка подключиться к уже запущенному приложению. - Подключен = Ложь; - Попытка - ПодключенныйТестКлиент.УстановитьСоединение(); - Подключен = Истина; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = "Ошибка соединения с тест-клиентом. Порт " + Порт + " - |" + ПодробноеПредставлениеОшибки(Инфо); - - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); - КонтекстЯдра.Отладка("ПодключитьТестКлиент: ОШИБКА: - | "+ОписаниеОшибки); - - Подключен = Ложь; - КонецПопытки; - - Если Подключен Тогда - Результат.Вставить("Клиент", ПодключенныйТестКлиент); - Результат.Вставить("Порт", Порт); - - СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); - ЗаписатьИнформациюВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("Тест-клиент подключен успешно. Порт ""%1"", PID клиента ""%2""", Порт, СведенияОЗанятыхПортах.Процессы[Порт]))); - Возврат Результат; - КонецЕсли; - - СтрокаЗапуска = СтрокаЗапускаТестКлиента(ИмяПользователя, Пароль, Порт, ДопПараметры); - - УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); - УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(СтрокаЗапуска, Ложь, Ложь); - - ВремяОкончанияОжидания = ТекущаяДата() + ТаймаутВСекундах(); - ОписаниеОшибкиСоединения = ""; - СчетчикПопыток = 0; - Пока Не ТекущаяДата() >= ВремяОкончанияОжидания Цикл - Попытка - СчетчикПопыток = СчетчикПопыток + 1; - - Если Не ТестКлиентЗапущен(Порт) Тогда - ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("Не запущен процесс тест-клиента на порту %1", Порт)); - Прервать; - КонецЕсли; - - ПодключенныйТестКлиент.УстановитьСоединение(); - Подключен = Истина; - Прервать; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = СтрШаблон("Попытка %1. Ошибка подключения тест-клиента. Порт %2 - |%3", СчетчикПопыток, Порт, ПодробноеПредставлениеОшибки(Инфо)); - - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); - КонтекстЯдра.Отладка("ПодключитьТестКлиент: " + ОписаниеОшибки); - КонецПопытки; - КонецЦикла; - - Если Не Подключен Тогда - ВызватьИсключение КонтекстЯдра.Отладка(СтрШаблон( - "ПодключитьТестКлиент: Не смогли установить соединение с тестовым приложением для пользователя %1! - |%2", - ИмяПользователя, ОписаниеОшибкиСоединения)); - КонецЕсли; - - СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); - Если Подключен И ОсновноеОкно(ПодключенныйТестКлиент) = Неопределено Тогда - Таймаут = 5; - ДлительностьОжидания = 0; - Попытка - Пока ОсновноеОкно(ПодключенныйТестКлиент) = Неопределено И ДлительностьОжидания < ТаймаутВСекундах() Цикл - ПодключенныйТестКлиент.ПолучитьАктивноеОкно().Активизировать(); - ДлительностьОжидания = ДлительностьОжидания + Таймаут; - - Пауза(ПодключенныйТестКлиент, Таймаут); - КонецЦикла; - - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ОписаниеОшибкиСоединения = КраткоеПредставлениеОшибки(ИнформацияОбОшибке); - ПолныйТекстСообщения = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - - ЗаписатьПредупреждениеВЖурналРегистрации(ПолныйТекстСообщения); - - ВызватьИсключение КонтекстЯдра.Отладка(СтрШаблон( - "ru = 'ПодключитьТестКлиент: Не смогли получить основное окно тестового приложения (пользователь %1) - |%2!", ИмяПользователя, ОписаниеОшибкиСоединения)); - - КонецПопытки; - Если ОсновноеОкно(ПодключенныйТестКлиент) = Неопределено Тогда - ПодключенныйТестКлиент.НайтиОбъект(Тип("ТестируемаяКнопкаФормы"), "Отмена").Нажать(); - ПодключенныйТестКлиент.РазорватьСоединение(); - - ВызватьИсключение ЗаписатьОшибкуВЖурналеРегистрации(КонтекстЯдра.Отладка(НСтр("ru = 'ПодключитьТестКлиент: Превышено время ожидания ввода пароля.'"))); - КонецЕсли; - КонецЕсли; - - Результат.Вставить("Клиент", ПодключенныйТестКлиент); - Результат.Вставить("Порт", Порт); - - ЗаписатьИнформациюВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("ПодключитьТестКлиент: Тест-клиент подключен успешно. Порт ""%1"", PID клиента ""%2""", Порт, СведенияОЗанятыхПортах.Процессы[Порт]))); - - Возврат Результат; - -КонецФункции - -&НаКлиенте -Процедура ЗавершитьВсеТестКлиенты() Экспорт - - КонтекстЯдра.Отладка("Перед завершением всех тест-клиентов"); - - Если Не ЗначениеЗаполнено(ЗапущенныеТестКлиенты) Тогда - - КонтекстЯдра.Отладка(" - Не найдено запущенных тест-клиентов"); - Возврат; - - КонецЕсли; - - Для Каждого ТекЗначение Из ЗапущенныеТестКлиенты Цикл - - Порт = XMLСтрока(ТекЗначение.Порт); - КонтекстЯдра.Отладка(" - Нашли тест-клиент. Порт " + Порт); - - Если ЭтоLinux() Тогда - ЗапуститьПриложение("kill -9 `ps aux | grep -ie TESTCLIENT | grep -ie 1cv8c | awk '{print $2}'`"); - Иначе - ТекстСкрипта = ТекстСкриптаЗавершитьТестКлиент(Порт); - КонтекстЯдра.Отладка(" - текст скрипта удаления. " + ТекстСкрипта); - - КодВозврата = Неопределено; - ЗапуститьПриложение("cmd /c" + ТекстСкрипта,, Истина, КодВозврата); - Если ЗначениеЗаполнено(КодВозврата) Тогда - КонтекстЯдра.Отладка(СтрШаблон(" - После запуска команды завершения тест-клиента. КодВозврата: %1, Порт %2", КодВозврата, Порт)); - Иначе - КонтекстЯдра.Отладка(" - После запуска команды завершения тест-клиента. Порт " + Порт); - КонецЕсли; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -&НаКлиенте -Функция ТестКлиентЗапущен(Порт) - - Результат = Ложь; - ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt"); // BSLLS:MissingTemporaryFileDeletion-off - - ЭтоLinux = ЭтоLinux(); - - П = XMLСтрока(Порт); - Если ЭтоLinux Тогда - ЗапуститьПриложение(СтрШаблон("ps aux | grep -ie TESTCLIENT | grep -ie 1cv8c | grep ""TPort[\s]*%1"" -iP > %2", П, ИмяВременногоФайла), , Истина); - Иначе - ТекстСкрипта = СтрЗаменить(ТекстСкриптаИнформацияОЗапущенныхКлиентах(П), "%", "%%") + " > " + ИмяВременногоФайла; - УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); - КодОтвета = УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(ТекстСкрипта, Истина); - КонецЕсли; - - Попытка - - Текст = Новый ЧтениеТекста(ИмяВременногоФайла, "UTF-8"); - КоличествоСтрок = СтрЧислоСтрок(Текст.Прочитать()); - - Результат = КоличествоСтрок > 0; - - Текст.Закрыть(); - - Исключение - - // стандарт по исключениям https://its.1c.ru/db/v8std/content/499/hdoc - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ЗаписатьПредупреждениеВЖурналРегистрации("Не прочитали файл - |" + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке), "ТестКлиентЗапущен"); - - Результат = Ложь; - КонецПопытки; - - Возврат Результат; -КонецФункции - -// Получить последнее (по порядку) открытое окно -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение -// -// Возвращаемое значение: -// ТестируемоеОкноКлиентскогоПриложения -// -&НаКлиенте -Функция ПервоеОкноИзСтека(ТестКлиент) Экспорт - ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); - Если ЗначениеЗаполнено(ОткрытыеОкна) Тогда - Возврат ОткрытыеОкна[0]; - КонецЕсли; - - Возврат Неопределено; -КонецФункции - -&НаКлиенте -Функция ТестКлиентПоУмолчанию() Экспорт - - Если ЗначениеЗаполнено(ЗапущенныеТестКлиенты) Тогда - Текст = СтрШаблон("ПодключитьТестКлиент: Был использован один из запущенных ранее тест-клиентов. - | ИмяПользователя: %1 - | Порт: %2 - | ДопПараметры: %3", ЗапущенныеТестКлиенты[0].ИмяПользователя, - ЗапущенныеТестКлиенты[0].Порт, - ЗапущенныеТестКлиенты[0].ДопПараметры); - - ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(Текст)); - Возврат ЗапущенныеТестКлиенты[0].ТестКлиент; - КонецЕсли; - - ОписаниеТестКлиента = ПодключитьТестКлиент(); - Результат = ОписаниеТестКлиента.Клиент; - - ЗапомнитьДанныеТестКлиента(Результат, "", ОписаниеТестКлиента.Порт, ""); - - Текст = СтрШаблон("ПодключитьТестКлиент: Был запущен новый тест-клиент. - | Порт: %1", ОписаниеТестКлиента.Порт); - ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(Текст)); - - Возврат Результат; -КонецФункции - -&НаКлиенте -Функция ТестКлиентПоПараметрам(Знач ИмяПользователя = "", Знач Пароль = "", Знач Порт = 0, - Знач ДопПараметры = "") Экспорт - Порт = ПолучитьПорт(Порт); - - Результат = НайтиЗапущенныйКлиент(ИмяПользователя, Порт); - Если Результат <> Неопределено Тогда - Возврат Результат; - КонецЕсли; - - ОписаниеТестКлиента = ПодключитьТестКлиент(ИмяПользователя, Пароль, Порт, ДопПараметры); - Результат = ОписаниеТестКлиента.Клиент; - - ЗапомнитьДанныеТестКлиента(Результат, ИмяПользователя, ОписаниеТестКлиента.Порт, ДопПараметры); - - Возврат Результат; - -КонецФункции - -// Идентифицировать окно предупреждение -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения -// Пояснение - Строка - Доп информация для вывода в содержимое ошибки -// ИгнорируемыйМассивТекстовИсключений - Массив, Неопределено - Массив строк содержащий исключения для игнорирования -// ОкнаДо - Соответствие - открытые окна до проверки. на их основе вычисляются новые открытые окна, чтобы не перебирать все окна тест-клиента. Важно для ускорения! -// -&НаКлиенте -Процедура ИдентифицироватьОкноПредупреждение(Знач ТестКлиент, Знач Пояснение = "", ИгнорируемыйМассивТекстовИсключений = Неопределено, - Знач ОкнаДо = Неопределено) Экспорт - - // 1. проверяем наличие ошибки - ТекущаяИнформацияОбОшибке = ТестКлиент.ПолучитьТекущуюИнформациюОбОшибке(); - Если ТипЗнч(ТекущаяИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда - ПодробноеПредставлениеОшибки = ПодробноеПредставлениеОшибки(ТекущаяИнформацияОбОшибке); - КраткоеПредставление = КраткоеПредставлениеОшибки(ТекущаяИнформацияОбОшибке); - - Если ИгнорируемыйМассивТекстовИсключений <> Неопределено И МассивСодержит(ИгнорируемыйМассивТекстовИсключений, КраткоеПредставление) Тогда - ПодробноеПредставлениеОшибки = ""; - КонтекстЯдра.Отладка(СтрШаблон("ОКНА: Пропустили исключение при открытии окна. - | Текст ошибки: ""%1""", КраткоеПредставление)); - Иначе - ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("ИдентифицироватьОкноПредупреждение выявило ошибку: - |""%1""", ПодробноеПредставлениеОшибки), КлючНастройкиМодальныхОкон()); - КонецЕсли; - - Если ЗначениеЗаполнено(ПодробноеПредставлениеОшибки) Тогда // могут быть исключения для ошибок - ЗакрытьВсеОткрытыеОкна(ТестКлиент); - КонтекстЯдра.ВызватьОшибкуПроверки(СтрШаблон("Выявлена ошибка: ""%1""", ПодробноеПредставлениеОшибки)); - Иначе - НажатьОК(ТестКлиент); - КонецЕсли; - Иначе - Ошибка = ТекстСистемногоОкнаОшибки(ТестКлиент, ОкнаДо); - Если ЗначениеЗаполнено(Ошибка) Тогда - Если Не ЗначениеЗаполнено(ИгнорируемыйМассивТекстовИсключений) ИЛИ Не МассивСодержит(ИгнорируемыйМассивТекстовИсключений, Ошибка) Тогда - ЗакрытьВсеОткрытыеОкна(ТестКлиент); - КонтекстЯдра.ВызватьОшибкуПроверки(СтрШаблон("Выявлено окно с ошибкой: ""%1""", Ошибка)); - Иначе - НажатьОК(ТестКлиент); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - // при совершении различных действий тестом (открытие формы, клик по кнопке) может появиться окно длительной операции - // если оно открыто, ждем n секунд, пока не закроется. если не закроется, выдается ошибка - ОкноДлительныхОпераций = ОкноДлительныхОпераций(ТестКлиент); - Если ОкноДлительныхОпераций <> Неопределено И Не ОкноДлительныхОпераций.ОжидатьЗакрытие(15) Тогда - КонтекстЯдра.ВызватьОшибкуПроверки("Тест прерван. Не дождались закрытия окна длительных операций"); - КонецЕсли; - - // 2. Проверяем наличие новых окон, пробуем их закрыть (просто закрыть, модальные в соответствии с настройками) - // закрыть все окна было бы неверно, т.к. могут быть случаи, когда открыли форму объекта и в этой форме выполняем различные действия (кликаем по строкам, переходим по ком. интерфейсу) - // такое поведение есть в тесты_КомандныйИнтерфейс, и нужно закрывать только те окна, которые появились после выполняемых действий, форму объекта не должны трогать - СписокПропускаемыхФорм.Очистить(); - ЗакрытьВсеОткрытыеОкнаСУчетомНастроек(ТестКлиент, ОкнаДо); -КонецПроцедуры - -// не все ошибки ловятся через ТестКлиент.ПолучитьТекущуюИнформациюОбОшибке(), например ошибки дин. списка так не поймать -// у таких ошибок ИмяФормы ErrorWindow -&НаКлиенте -Функция ТекстСистемногоОкнаОшибки(Знач ТестКлиент, Знач ОкнаДо) - - Если ЗначениеЗаполнено(ОкнаДо) Тогда - НовыеОткрытыеОкна = НовыеОткрытыеОкна(ТестКлиент, ОкнаДо); - ОткрытыеОкна = МассивОткрытыхОкон(НовыеОткрытыеОкна); - Иначе - ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); - КонецЕсли; - Для Каждого ТекОкно Из ОткрытыеОкна Цикл - Объекты = ТекОкно.ПолучитьПодчиненныеОбъекты(); - Для Каждого ОбъектОкна Из Объекты Цикл - // Заголовок "1С:Предприятие" - Если Тип(ОбъектОкна) = Тип("ТестируемаяФорма") И ОбъектОкна.ИмяФормы = "ErrorWindow" Тогда - Возврат СодержимоеОкна(ТекОкно) - КонецЕсли; - КонецЦикла; - КонецЦикла; - - Возврат ""; -КонецФункции - -&НаКлиенте -Функция ПоявилосьОкноПредупрежденияСТекстом(Знач ТестКлиент, Знач ТекстИсключенияДляПроверки, Знач ОкнаДо) Экспорт - Перем ОкноПредупреждение; - - //ПодчиненныеОбъекты = ПодчиненныеОбъекты(ТестКлиент); - //Для Каждого ПодчиненныйОбъект Из ПодчиненныеОбъекты Цикл - ВсеОткрытыеОкна = ОткрытыеОкнаИзМассиваОкон(ПодчиненныеОбъекты(ТестКлиент)); - ОткрытыеОкна = ИсключитьРанееОткрытыеОкна(ВсеОткрытыеОкна, ОкнаДо); - - Для Каждого КлючЗначение Из ОткрытыеОкна Цикл - ПодчиненныйОбъект = КлючЗначение.Значение; - Если ТипЗнч(ПодчиненныйОбъект) <> Тип("ТестируемоеОкноКлиентскогоПриложения") Тогда - Продолжить; - КонецЕсли; - Если ПодчиненныйОбъект.Основное Или ПодчиненныйОбъект.НачальнаяСтраница Тогда - Продолжить; - КонецЕсли; - - Если НайтиОписаниеМодальногоОкна(ПодчиненныйОбъект) <> Неопределено Тогда - ОкноПредупреждение = ПодчиненныйОбъект; - Прервать; - КонецЕсли; - КонецЦикла; - - ТекстИсключения = СодержимоеОкна(ОкноПредупреждение); // проверка на неопределено внутри - - Возврат ЗначениеЗаполнено(ТекстИсключения) И Найти(ВРег(ТекстИсключения), ВРег(ТекстИсключенияДляПроверки)) > 0; -КонецФункции - -&НаКлиенте -Процедура НажатьОК(ТестКлиент) - ОкноОшибки = ПервоеОкноИзСтека(ТестКлиент); - Если ОкноОшибки = Неопределено Тогда - Возврат; - КонецЕсли; - - Кнопки = ПолучитьКнопки(ОкноОшибки); - Для Каждого Кнопка Из Кнопки Цикл - Если ВРег(Кнопка.Имя) = "OK" ИЛИ ВРег(Кнопка.Имя) = "ОК" Тогда // латиница и кириллица - Кнопка.Нажать(); - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -&НаКлиенте -Функция НайтиОписаниеМодальногоОкна(ОкноПриложения) - Перем Поля; - - Если КонтекстЯдра.ОтладкаВключена() Тогда - КонтекстЯдра.Отладка(СтрШаблон(" -->> НайтиОписаниеМодальногоОкна - заголовок окна %1, %2", - ОкноПриложения.Заголовок, СодержимоеОкна(ОкноПриложения))); - КонецЕсли; - - // Если в настройках задан заголовок и поля, отбор по "И" - // если на этом этапе ОписаниеМодальногоОкна = неопределено, значит, нет подходящего описания для заголовка - // возможно, в описании заданы только поля, а заголовка нет, тогда ищем по полям. ОписаниеМодальногоОкна <> неопределено, мы должны проверить поля именно этого описания - // если проверять по ПоляМодальныхОкон, можно получить ситуацию, когда заголовок из одной настройки, а поля из другой. - - // НайтиПодходящееЗначениеПоКлючуВКоллекции должен возвращать массив, т.к. для обеспечения указанной логики работы может быть несколько правил (описаний) - // с одним и тем же заголовком, но разными полями и разными кнопками. Т.е. поля - это способ уточнить поиск окна, заголовок первичнее - ОписанияМодальногоОкна = НайтиПодходящееЗначениеПоКлючуВКоллекции(ЗаголовкиМодальныхОкон, ОкноПриложения.Заголовок); - - Если ОписанияМодальногоОкна = Неопределено ИЛИ ОписанияМодальногоОкна.Количество() = 0 Тогда - - Если Не ЗначениеЗаполнено(ПоляМодальныхОкон) Тогда - Возврат Неопределено; - КонецЕсли; - РанееПроверенныеРезультаты = ДанныеКешаПроверкиОкон(ОкноПриложения); - Если ЗначениеЗаполнено(РанееПроверенныеРезультаты) Тогда - Возврат РанееПроверенныеРезультаты.Описание; - КонецЕсли; - - ПоляФормы = ОкноПриложения.НайтиОбъекты(Тип("ТестируемоеПолеФормы")); - РезультатПоиска = НайтиОписаниеМодальногоОкнаДляПолейФормы(ПоляФормы, ПоляМодальныхОкон); - Если РезультатПоиска.Успешно Тогда - ДобавитьВКешПроверкиОкон(ОкноПриложения, Истина, РезультатПоиска.Описание); - Возврат РезультатПоиска.Описание; - КонецЕсли; - - ПоляФормы = ОкноПриложения.НайтиОбъекты(Тип("ТестируемаяДекорацияФормы")); - РезультатПоиска = НайтиОписаниеМодальногоОкнаДляПолейФормы(ПоляФормы, ПоляМодальныхОкон); - Если РезультатПоиска.Успешно Тогда - ДобавитьВКешПроверкиОкон(ОкноПриложения, Истина, РезультатПоиска.Описание); - Возврат РезультатПоиска.Описание; - КонецЕсли; - - ДобавитьВКешПроверкиОкон(ОкноПриложения, Ложь, Неопределено); - Возврат Неопределено; - - КонецЕсли; - - Если ЗначениеЗаполнено(ОписанияМодальногоОкна) Тогда - ПоляФормы = Неопределено; - - // отбор правил с заголовком и с полями - Для Каждого Описание Из ОписанияМодальногоОкна Цикл - Если Не Описание.Свойство("Поля", Поля) Тогда - Продолжить; - КонецЕсли; - - Если ПоляФормы = Неопределено Тогда - ПоляФормы = Новый Массив(); - ДополнитьМассив(ПоляФормы, ОкноПриложения.НайтиОбъекты(Тип("ТестируемоеПолеФормы"))); - ДополнитьМассив(ПоляФормы, ОкноПриложения.НайтиОбъекты(Тип("ТестируемаяДекорацияФормы"))); - КонецЕсли; - - Для Каждого ТекстПоля Из Поля Цикл - ТекстПоляДляСравнения = ДляСравнения(ТекстПоля); - Для Каждого ТекПолеФормы Из ПоляФормы Цикл - Если КонтекстЯдра.СтрокаСоответствуетШаблону(ДляСравнения(ТекПолеФормы.ТекстЗаголовка), ТекстПоляДляСравнения) Тогда - Возврат Описание; - КонецЕсли; - КонецЦикла; - КонецЦикла; - КонецЦикла; - - // отбор правил без полей, но с заголовком - // если не нашли подходящее описание по полям, вернем первое подходящее без полей только с заголовком - Для Каждого Описание Из ОписанияМодальногоОкна Цикл - Если Не Описание.Свойство("Поля", Поля) Тогда - Возврат Описание; - КонецЕсли; - КонецЦикла; - - КонецЕсли; - - Возврат Неопределено; -КонецФункции - -&НаКлиенте -Функция НайтиОписаниеМодальногоОкнаДляПолейФормы(ПоляФормы, ПоляМодальныхОкон) - - Результат = Новый Структура("Успешно, Описание", Ложь, Неопределено); - - // отбор правил без заголовка, но с полями - Для Каждого ТекПолеФормы Из ПоляФормы Цикл - Настройки = НайтиПодходящееЗначениеПоКлючуВКоллекции(ПоляМодальныхОкон, ТекПолеФормы.ТекстЗаголовка); - Если Настройки = Неопределено Тогда - Продолжить; - КонецЕсли; - - Для Каждого Описание Из Настройки Цикл - // интересуют те описания, у которых нет заголовка, по заголовку поиск выше - Если Не Описание.Свойство("Заголовки") Тогда - Результат.Успешно = Истина; - Результат.Описание = Описание; - Возврат Результат; - КонецЕсли; - КонецЦикла; - КонецЦикла; - - Возврат Результат; -КонецФункции - -&НаКлиенте -// Возвращает основное окно текущего тест-клиента -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение - ТестируемоеПриложение -// -// Возвращаемое значение: -// ТестируемоеОкноКлиентскогоПриложения - или Неопределено, если не нашли или ошибка сетевого взаимодействия -// -Функция ОсновноеОкно(ТестКлиент) Экспорт - Попытка - КлиентскиеОкнаТестируемогоПриложения = ПодчиненныеОбъекты(ТестКлиент); - Для Каждого ТекОкно Из КлиентскиеОкнаТестируемогоПриложения Цикл - Если ТекОкно.Основное Тогда - Возврат ТекОкно; - КонецЕсли; - КонецЦикла; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = "Ошибка поиска основного окна тест-клиента. - |" + ПодробноеПредставлениеОшибки(Инфо); - - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); - - Возврат Неопределено; - КонецПопытки; - - Возврат Неопределено; -КонецФункции - -&НаКлиенте -Процедура Пауза(ТестКлиент, КоличествоСекунд) Экспорт - - ТестКлиент.ОжидатьОтображениеОбъекта(Тип("ТестируемаяФорма"), "ЗаведомоОтсутствующийОбъект",, КоличествоСекунд); - -КонецПроцедуры - -&НаКлиенте -Функция СодержимоеОкна(ОкноПредупреждение) Экспорт - Перем Содержимое; - - Если ОкноПредупреждение = Неопределено Тогда - Возврат ""; - КонецЕсли; - - Для Каждого ТекДекорацияФормы Из ОкноПредупреждение.НайтиОбъекты(Тип("ТестируемаяДекорацияФормы")) Цикл - Если ТекДекорацияФормы.Имя = "Message" Тогда - Содержимое = ТекДекорацияФормы.ТекстЗаголовка; - ИначеЕсли ТекДекорацияФормы.Имя = "ErrorInfo" Тогда - Содержимое = ТекДекорацияФормы.ТекстЗаголовка; - КонецЕсли; - КонецЦикла; - - Если Содержимое = Неопределено Тогда - ТекстыЗаголовков = Новый Массив; - Для Каждого ТекПолеФормы Из ОкноПредупреждение.НайтиОбъекты(Тип("ТестируемоеПолеФормы")) Цикл - Если ЗначениеЗаполнено(ТекПолеФормы.ТекстЗаголовка) Тогда - ТекстыЗаголовков.Добавить(ТекПолеФормы.ТекстЗаголовка); - КонецЕсли; - КонецЦикла; - Содержимое = УкоротитьСтроку(СтрСоединить(ТекстыЗаголовков, ", "), 100); - КонецЕсли; - - Возврат СтрШаблон("Заголовок: <%1>; Содержимое: <%2>", ОкноПредупреждение.Заголовок, Содержимое); -КонецФункции - -&НаКлиенте -Функция УкоротитьСтроку(Знач Стр, Длина) - Стр2 = Лев(Стр, Длина); // нет смысла выводить длинную портянку - Возврат ?(СтрДлина(Стр2) < СтрДлина(Стр), Стр2+"...", Стр2); -КонецФункции - -// Возвращает заголовок и содержимое открытых окон -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения - -// -// Возвращаемое значение: -// Строка - Строка разделенная переносом строк, каждая строчка это представление окна -// -&НаКлиенте -Функция ПредставленияОткрытыхОкон(ТестКлиент) Экспорт - ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); - ОписанияОкон = Новый Массив(); - Для а = 0 По ОткрытыеОкна.ВГраница() Цикл - Если ОткрытыеОкна[а].Основное ИЛИ ОткрытыеОкна[а].НачальнаяСтраница - ИЛИ ТипЗнч(ОткрытыеОкна[а]) <> Тип("ТестируемоеОкноКлиентскогоПриложения") Тогда - Продолжить; - КонецЕсли; - - ОписанияОкон.Добавить(СтрШаблон("[%1] %2", а, СодержимоеОкна(ОткрытыеОкна[а]))); - КонецЦикла; - - Возврат СтрСоединить(ОписанияОкон, Символы.ПС); -КонецФункции - -&НаКлиенте -Процедура ЗакрытьВсеОткрытыеОкна(ТестКлиент) Экспорт - КонтекстЯдра.Отладка("ОКНА: Закрываем все открытые окна"); - - СписокПропускаемыхФорм.Очистить(); - - ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); - Для Каждого ТекОкно Из ОткрытыеОкна Цикл - //Если ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда - // Продолжить; - //КонецЕсли; - Если ПропуститьОкно(ТекОкно) Тогда - КонтекстЯдра.Отладка(СтрШаблон(" -->> Окно пропущено ""%1""", ТекОкно.Заголовок)); - Продолжить; - КонецЕсли; - - Попытка - ТекОкно.Закрыть(); - КонтекстЯдра.Отладка(СтрШаблон(" -->> Закрыли окно ""%1""", ТекОкно.Заголовок)); - Исключение - // Необходимо принудительно закрыть все окна, специальная обработка исключений не требуется. - СписокПропускаемыхФорм.Добавить(ТекОкно.Заголовок); - КонтекстЯдра.Отладка(СтрШаблон(" -->> Ошибка закрытия окна ""%1""", ТекОкно.Заголовок)); - КонецПопытки; - КонецЦикла; -КонецПроцедуры - -// Закрываются все открытые окна с учетом настроек -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения - -// ОкнаДо - Соответствие, Неопределено - Необязательный. -// -&НаКлиенте -Процедура ЗакрытьВсеОткрытыеОкнаСУчетомНастроек(ТестКлиент, Знач ОкнаДо = Неопределено) Экспорт - КонтекстЯдра.Отладка("ОКНА: Закрываем все новые окна с учетом настроек, ранее открытые окна не закрываем"); - - Если Не ЗначениеЗаполнено(ОкнаДо) Тогда - ОкнаДо = КонструкторОткрытыеОкна(); - КонецЕсли; - - ВсеОткрытыеОкна = ОткрытыеОкнаИзМассиваОкон(ПодчиненныеОбъекты(ТестКлиент)); - ОткрытыеОкна = ИсключитьРанееОткрытыеОкна(ВсеОткрытыеОкна, ОкнаДо); - - Для Каждого КлючЗначение Из ОткрытыеОкна Цикл - ТекОкно = КлючЗначение.Значение; - Если ПропуститьОкно(ТекОкно) - ИЛИ ТипЗнч(ТекОкно) <> Тип("ТестируемоеОкноКлиентскогоПриложения") Тогда - Продолжить; - КонецЕсли; - - Кнопки = ПолучитьКнопки(ТекОкно); - Если Не ЗначениеЗаполнено(Кнопки) Тогда - Продолжить; - КонецЕсли; - - ОписаниеМодальногоОкна = НайтиОписаниеМодальногоОкна(ТекОкно); - ОкноЗакрыто = Ложь; - Если ОписаниеМодальногоОкна = Неопределено Тогда - // много "ошибочных" кликов по кнопке на форме документа, справочника. - // Был пример где на форме кнопка "конструктор запросов" и тест на нее клиекает, что открывает конструктор и далее тест ходит по вкладкам конструктора запросов, что вообще не нужно - // лучше для окон с ошибкой или модальных задавать правила через настройки - //ОкноЗакрыто = НажатьКнопкуМодальногоДиалогаЕслиНаФормеВсегоОднаКнопка(Кнопки, ТекОкно.Заголовок); - Иначе - ОкноЗакрыто = ЗакрытьОкноПредупреждения(Кнопки, ТекОкно, ОписаниеМодальногоОкна); - КонецЕсли; - - СписокПропускаемыхФорм.Добавить(ТекОкно.Заголовок); - Если ОкноЗакрыто Тогда - КонтекстЯдра.Отладка(СтрШаблон(" -->> Закрыли окно ""%1""", ТекОкно.Заголовок)); - УдалитьИзКешаПроверкиОкон(ТекОкно); - - // успешное нажатие на кнопку может повторно открыть модальное окно, например, при закрытии формы документа появляется вопрос - // "сохранить?"" жмется "да", появляется еще окно "произвести перерасчет?" - ЗакрытьВсеОткрытыеОкнаСУчетомНастроек(ТестКлиент, ОкнаДо); - Иначе - КонтекстЯдра.Отладка(СтрШаблон(" -->> Настроек для окна ""%1"" не найдено", ТекОкно.Заголовок)); - КонецЕсли; - КонецЦикла; -КонецПроцедуры - -&НаКлиенте -Функция ОкноДлительныхОпераций(ТестКлиент) - ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); - Для Каждого ТекОкно Из ОткрытыеОкна Цикл - Если ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда - Продолжить; - КонецЕсли; - - Форма = ТекОкно.НайтиОбъект(Тип("ТестируемаяФорма")); - Если Форма <> Неопределено И Форма.ИмяФормы = "ОбщаяФорма.ДлительнаяОперация" Тогда - Возврат Форма; - КонецЕсли; - КонецЦикла; - - Возврат Неопределено; -КонецФункции - -&НаКлиенте -Функция ПолучитьКнопки(Окно) - Кнопки = Новый Массив(); - Попытка - Для Каждого Кнопуля Из Окно.НайтиОбъекты(Тип("ТестируемаяКнопкаФормы")) Цикл - Если Кнопуля.Вид = ВидКнопкиФормы.ОбычнаяКнопка ИЛИ Кнопуля.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели И Не СтрНачинаетсяС_(Кнопуля.ТекстЗаголовка, "Command") Тогда - Кнопки.Добавить(Кнопуля); - КонтекстЯдра.Отладка(СтрШаблон(" -->> ОКНА: %1. Кнопка ""%2"", Заголовок ""%3""", Кнопки.Количество(), Кнопуля.Имя, Кнопуля.ТекстЗаголовка)); - КонецЕсли; - КонецЦикла; - Исключение - Возврат Кнопки; - КонецПопытки; - - Возврат Кнопки; -КонецФункции - -&НаКлиенте -Функция ПропуститьОкно(ТекОкно) - - Если ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда - Возврат Истина; - КонецЕсли; - - // В массив добавляем окна, на которых уже вылезали ошибки - Если СписокПропускаемыхФорм.НайтиПоЗначению(ТекОкно.Заголовок) <> Неопределено Тогда - Возврат Истина; - КонецЕсли; - - Возврат Ложь; -КонецФункции - -&НаКлиенте -Функция ЗакрытьОкноПредупреждения(Кнопки, ОкноПриложения, ОписаниеМодальногоОкна) - Результат = Ложь; - - ОкноПриложения.Активизировать(); - Если ОписаниеМодальногоОкна <> Неопределено И НажатьКнопкуМодальногоДиалога(ОписаниеМодальногоОкна, Кнопки) Тогда - КонтекстЯдра.Отладка(СтрШаблон("ОКНА: Успешный клик по кнопке окна <%1>", ОкноПриложения.Заголовок)); - Результат = Истина; - Иначе - КонтекстЯдра.Отладка(СтрШаблон("ОКНА: Не удалось нажать на кнопку окна <%1>", ОкноПриложения.Заголовок)); - КонецЕсли; - - Возврат Результат; -КонецФункции - -// Возвращает открытые окна -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение - тест-клиент -// -// Возвращаемое значение: -// Соответствие - ключ - заголовок окна, символы * удалены, значение - само окно -// -&НаКлиенте -Функция ОткрытыеОкна(ТестКлиент) Экспорт - - ВсеОкна = ТестКлиент.НайтиОбъекты(Тип("ТестируемоеОкноКлиентскогоПриложения")); - - Возврат ОткрытыеОкнаИзМассиваОкон(ВсеОкна); -КонецФункции - -&НаКлиенте -Функция КонструкторОткрытыеОкна() - Возврат Новый Соответствие; -КонецФункции - -&НаКлиенте -Функция ОткрытыеОкнаИзМассиваОкон(Знач ВсеОкна) - ОткрытыеОкна = КонструкторОткрытыеОкна(); - - Для Каждого ТекОкно Из ВсеОкна Цикл - Если ТекОкно = Неопределено Или ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда - Продолжить; - КонецЕсли; - Заголовок = НормализоватьЗаголовокОкна(ТекОкно); - ОткрытыеОкна.Вставить(Заголовок, ТекОкно); - КонецЦикла; - - Возврат ОткрытыеОкна; -КонецФункции - -&НаКлиенте -Функция МассивОткрытыхОкон(Знач ОткрытыеОкна) - Результат = Новый Массив; - - Для Каждого КлючЗначение Из ОткрытыеОкна Цикл - Результат.Добавить(КлючЗначение.Значение); - КонецЦикла; - - Возврат Результат; -КонецФункции - -// Нормализовать заголовок окна, из заголовка удаляются хвостовые пробелы и *, -// т.к. не нужно различать, если у формы взведен флаг модифицированности -// -// Параметры: -// ТекОкно - Произвольный -// -// Возвращаемое значение: -// Строка - заголовок без хвостовых пробелов и * -// -&НаКлиенте -Функция НормализоватьЗаголовокОкна(Знач ТекОкно) Экспорт - Возврат СокрЛП(СтрЗаменить(ТекОкно.Заголовок, "*", "")); -КонецФункции - -// Возвращает новые открытые окна -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение - тест-клиент -// ОткрытыеОкнаДо - Соответствие - ранее открытые окна -// -// Возвращаемое значение: -// Соответствие - ключ - заголовок окна, символы * удалены, значение - само окно -// -&НаКлиенте -Функция НовыеОткрытыеОкна(ТестКлиент, Знач ОткрытыеОкнаДо) Экспорт - - ОткрытыеОкна = ОткрытыеОкна(ТестКлиент); - Возврат ИсключитьРанееОткрытыеОкна(ОткрытыеОкна, ОткрытыеОкнаДо); -КонецФункции - -// Возвращает только новые открытые окна, без учета уже существующих окон -// -// Параметры: -// ОткрытыеОкна - Соответствие - все открытые окна -// ОткрытыеОкнаДо - Соответствие - ранее открытые окна, которые нужно исключить из списка -// ДелатьКопиюРезультата - Булево - необязательный. Делать копию результата -// для исключения изменения исходной коллекции ОткрытыеОкна -// -// Возвращаемое значение: -// Соответствие - ключ - заголовок окна, символы * удалены, значение - само окно -// -&НаКлиенте -Функция ИсключитьРанееОткрытыеОкна(Знач ОткрытыеОкна, Знач ОткрытыеОкнаДо, Знач ДелатьКопиюРезультата = Ложь) Экспорт - - Результат = КонструкторОткрытыеОкна(); - Для каждого КлючЗначение Из ОткрытыеОкна Цикл - Результат.Вставить(КлючЗначение.Ключ, КлючЗначение.Значение); - КонецЦикла; - - Если ЗначениеЗаполнено(ОткрытыеОкнаДо) Тогда - Для Каждого КлючЗначение Из ОткрытыеОкнаДо Цикл - Результат.Удалить(КлючЗначение.Ключ); - КонецЦикла; - КонецЕсли; - - Возврат Результат; -КонецФункции - -&НаКлиенте -Процедура ПроверитьНаНовыеМодальныеОкна(ТестКлиент, ОткрытыеОкнаДо) Экспорт - Если ОткрытыеОкнаДо = Неопределено ИЛИ ТестКлиент = Неопределено Тогда - Возврат; - КонецЕсли; - - Заголовки = Новый Массив(); - НужноВыброситьИсключение = Ложь; - Попытка - ОткрытыеОкна = ТестКлиент.НайтиОбъекты(Тип("ТестируемоеОкноКлиентскогоПриложения")); - Для Каждого ТекОкно Из ОткрытыеОкна Цикл - Заголовок = НормализоватьЗаголовокОкна(ТекОкно); - - Если ТекОкно = Неопределено Или ТекОкно.Основное Или ТекОкно.НачальнаяСтраница - Или ОткрытыеОкнаДо.Получить(Заголовок) <> Неопределено Тогда - Продолжить; - КонецЕсли; - - Заголовки.Добавить(ТекОкно.Заголовок); - НужноВыброситьИсключение = Истина; - КонецЦикла; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = "Ошибка поиска основного окна тест-клиента. - |" + ПодробноеПредставлениеОшибки(Инфо); - - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); - - КонтекстЯдра.ВывестиСообщение("Не удалось проверить модальные окна ", - СтатусСообщения.ОченьВажное); - - Возврат; - КонецПопытки; - - Если НужноВыброситьИсключение Тогда - ТекстИсключения = КонтекстЯдра.СтрШаблон_(" - |Выявлено окно, которое не закрывается! Возможно, это модальное окно. - |Текущее окно: %1 - |Открытые окна: - |%2", СодержимоеОкна(ТекОкно), СтрСоединить(Заголовки, Символы.Таб + Символы.ПС)); - ВызватьИсключение ТекстИсключения; - КонецЕсли; - -КонецПроцедуры - -&НаКлиенте -Процедура УстановитьНастройкиМодальныхОкон(Знач ПарамНастройкиМодальныхОкон, Знач ЗаголовкиСистемныхОкон = Неопределено) Экспорт - - Если Не ЗначениеЗаполнено(ПарамНастройкиМодальныхОкон) Тогда - Возврат; - КонецЕсли; - Если Не ЗначениеЗаполнено(ЗаголовкиСистемныхОкон) Тогда - ЗаголовкиСистемныхОкон = ЗаголовкиСистемныхОкон(); - КонецЕсли; - - Если НастройкиМодальныхОкон <> ПарамНастройкиМодальныхОкон Тогда - Для Каждого КлючЗначение Из ПарамНастройкиМодальныхОкон Цикл - НастройкиМодальныхОкон.Вставить(КлючЗначение.Ключ, КлючЗначение.Значение); - КонецЦикла; - КонецЕсли; - - ЗаголовкиМодальныхОкон = Новый Соответствие; - Для Каждого КлючЗначение Из НастройкиМодальныхОкон Цикл - Описание = КлючЗначение.Значение; - Если ТипЗнч(Описание) <> Тип("Структура") Тогда - Продолжить; - КонецЕсли; - - Заголовки = Неопределено; - Если Не Описание.Свойство("Заголовки", Заголовки) Тогда - Заголовки = ЗаголовкиСистемныхОкон; - КонецЕсли; - //Если Описание.Свойство("Заголовки", Заголовки) Тогда - Для Каждого Заголовок Из Заголовки Цикл - ЗаголовокДляСравнения = ДляСравнения(Заголовок); - Если ЗаголовкиМодальныхОкон[ЗаголовокДляСравнения] = Неопределено Тогда - ЗаголовкиМодальныхОкон[ЗаголовокДляСравнения] = Новый Массив(); - КонецЕсли; - - ЗаголовкиМодальныхОкон[ЗаголовокДляСравнения].Добавить(Описание); - КонецЦикла; - //КонецЕсли; - - Поля = Неопределено; - Если Описание.Свойство("Поля", Поля) Тогда - Для Каждого ТекстПоля Из Поля Цикл - ТекстПоляДляСравнения = ДляСравнения(ТекстПоля); - Если ПоляМодальныхОкон[ТекстПоляДляСравнения] = Неопределено Тогда - ПоляМодальныхОкон[ТекстПоляДляСравнения] = Новый Массив(); - КонецЕсли; - - ПоляМодальныхОкон[ТекстПоляДляСравнения].Добавить(Описание); - КонецЦикла; - КонецЕсли; - - КонецЦикла; - - Если КонтекстЯдра.ОтладкаВключена() Тогда - Для каждого КлючЗначение Из ЗаголовкиМодальныхОкон Цикл - ЗаголовокДляСравнения = КлючЗначение.Ключ; - Описания = КлючЗначение.Значение; - КонтекстЯдра.Отладка(СтрШаблон(" -->> ЗаголовкиМодальныхОкон - заголовок окна %1", ЗаголовокДляСравнения)); - Для каждого Описание Из Описания Цикл - Кнопка = Неопределено; - Описание.Свойство("Кнопка", Кнопка); - КонтекстЯдра.Отладка(СтрШаблон(" -->> ЗаголовкиМодальныхОкон - поле - описание.Кнопка %1", Кнопка)); - КонецЦикла; - КонецЦикла; - - Для каждого КлючЗначение Из ПоляМодальныхОкон Цикл - ТекстПоляДляСравнения = КлючЗначение.Ключ; - Описания = КлючЗначение.Значение; - КонтекстЯдра.Отладка(СтрШаблон(" -->> ПоляМодальныхОкон - текст поля %1", ТекстПоляДляСравнения)); - Для каждого Описание Из Описания Цикл - Кнопка = Неопределено; - Описание.Свойство("Кнопка", Кнопка); - КонтекстЯдра.Отладка(СтрШаблон(" -->> ПоляМодальныхОкон - поле - описание.Кнопка %1", Кнопка)); - КонецЦикла; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -&НаКлиенте -Функция ПолучитьНастройкиМодальныхОкон() Экспорт - Возврат НастройкиМодальныхОкон; -КонецФункции - -&НаКлиенте -Функция КлючНастройкиМодальныхОкон() Экспорт - Возврат "МодальныеОкна"; -КонецФункции - -// Найти свободный порт, если текущий\указанный порт занят другим процессом -// -// Параметры: -// Порт - Число - Необязательный. По умолчанию 1538 -// НачалоДиапазонаПортов - Число - Необязательный. По умолчанию 48000 -// ОкончаниеДиапазонаПортов - Число - Необязательный. По умолчанию 50000 -// -// Возвращаемое значение: -// Число - текущий порт или новый порт, если текущий занят -// -&НаКлиенте -Функция НайтиСвободныйПортЕслиТекущийЗанят(Знач Порт = 1538, Знач НачалоДиапазонаПортов = 48000, Знач ОкончаниеДиапазонаПортов = 50000) Экспорт - - Если Порт <= 0 Или Порт > 65536 Тогда - Порт = 1538; - КонецЕсли; - - СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); - МассивЗанятыхПортов = СведенияОЗанятыхПортах.Порты; - ПроцессыДляПортов = СведенияОЗанятыхПортах.Процессы; - - Если МассивЗанятыхПортов.Найти(Порт) <> Неопределено Тогда - Текст = СтрШаблон("Порт ""%1"" занят процессом pid: ""%2"" ", Порт, ПроцессыДляПортов[Порт]); - ЗаписатьПредупреждениеВЖурналРегистрации(Текст); - КонтекстЯдра.Отладка(Текст); - - Для СвободныйПорт = НачалоДиапазонаПортов По ОкончаниеДиапазонаПортов Цикл - Если МассивЗанятыхПортов.Найти(СвободныйПорт) = Неопределено Тогда - - Текст = СтрШаблон("Будет использован свободный порт: ""%1""", СвободныйПорт); - ЗаписатьПредупреждениеВЖурналРегистрации(Текст); - КонтекстЯдра.Отладка(Текст); - - Возврат СвободныйПорт; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Возврат Порт; - -КонецФункции - -// } Plugin interface - -// { Helpers -&НаСервере -Функция ЭтотОбъектНаСервере() - Возврат РеквизитФормыВЗначение("Объект"); -КонецФункции - -&НаКлиенте -Функция СтрокаЗапускаТестКлиента(Знач ИмяПользователя, Знач Пароль, Знач Порт, Знач ДопПараметры) - - Если Не ЗначениеЗаполнено(ИмяПользователя) Тогда - ИмяПользователя = ИмяТекущегоПользователя(); - КонецЕсли; - - СтрокаЗапуска1с = КаталогПрограммы() + "1cv8c"; - - Если Не ЭтоLinux() Тогда - СтрокаЗапуска1с = КонтекстЯдра.СтрШаблон_("%1.exe", СтрокаЗапуска1с); - КонецЕсли; - - Результат = КонтекстЯдра.СтрШаблон_( - """%1"" ENTERPRISE /IBConnectionString""%2""%3%4 /TestClient -TPort%5 /L%6 %7 /DisableStartupMessages /DisableStartupDialogs", - СтрокаЗапуска1с, - СтрЗаменить(СтрокаСоединенияИнформационнойБазы(), """", """"""), - ?(ПустаяСтрока(ИмяПользователя), "", " /N""" + ИмяПользователя + """"), - ?(ПустаяСтрока(Пароль), ""," /P""" + Пароль + """"), - XMLСтрока(Порт), - ТекущийЯзык(), - ДопПараметры); - - Возврат Результат; - -КонецФункции - -&НаСервереБезКонтекста -Функция ИмяТекущегоПользователя() - - ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь(); - - Если ТекущийПользователь.АутентификацияОС Тогда - Возврат ""; - Иначе - Возврат ТекущийПользователь.Имя; - КонецЕсли; - -КонецФункции - -&НаКлиенте -Функция ТаймаутВСекундах() - - Возврат 120; - -КонецФункции - -&НаКлиенте -Функция ТекстСкриптаЗавершитьТестКлиент(НомерПорта) - - Результат = СтрШаблон("%1 call terminate", ТекстСкриптаИнформацияОЗапущенныхКлиентах(НомерПорта)); - - Возврат Результат; -КонецФункции - -&НаКлиенте -Функция ТекстСкриптаИнформацияОЗапущенныхКлиентах(НомерПорта) - - Результат = - "wmic process where (CommandLine Like ""%/TESTCLIENT%"" And ExecutablePath Like ""%1cv8c%"") "; - - Если Не ЗначениеЗаполнено(НомерПорта) Тогда - Возврат Результат; - КонецЕсли; - - Возврат СтрЗаменить( - Результат, - "%/TESTCLIENT%", - "%/TESTCLIENT -TPort" + НомерПорта + "%"); - -КонецФункции - -&НаКлиенте -Функция ПолноеИмяИсполняемогоФайла() - - Возврат КонтекстЯдра.СтрШаблон_("%1%2%3", - КаталогПрограммы(), - "1cv8c", - РасширениеИсполняемогоФайла()); - -КонецФункции - -&НаКлиенте -Функция РасширениеИсполняемогоФайла() - - Если ЭтоLinux() Тогда - Возврат ""; - Иначе - Возврат ".exe"; - КонецЕсли; - -КонецФункции - -&НаКлиенте -Функция ЭтоLinux() - - СисИнфо = Новый СистемнаяИнформация; - ВерсияПриложения = СисИнфо.ВерсияПриложения; - - Возврат Найти(Строка(СисИнфо.ТипПлатформы), "Linux") > 0; - -КонецФункции - -// Записать примечание в журнал регистрации -// -// Параметры: -// ПостфиксСобытия - Строка - Может быть пустым -// Текст - - -// -&НаСервереБезКонтекста -Функция ЗаписатьОшибкуВЖурналеРегистрации(Знач ОписаниеОшибки, ПостфиксСобытия = "") - ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); // эта пляска для случаев когда ПостфиксСобытия будет пустой, что б в конце не осталась точка - ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки); - - Возврат ОписаниеОшибки; -КонецФункции - -// Записать примечание в журнал регистрации -// -// Параметры: -// ПостфиксСобытия - Строка - Может быть пустым -// Текст - - -// -&НаСервереБезКонтекста -Процедура ЗаписатьПредупреждениеВЖурналРегистрации(Знач ТекстОшибки, ПостфиксСобытия = "") - ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); - ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), - УровеньЖурналаРегистрации.Предупреждение, , , - ТекстОшибки); - -КонецПроцедуры - -&НаСервереБезКонтекста -Процедура ЗаписатьИнформациюВЖурналРегистрации(Знач Текст, ПостфиксСобытия = "") - ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); - ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), УровеньЖурналаРегистрации.Информация,,, Текст); -КонецПроцедуры - -// Записать примечание в журнал регистрации -// -// Параметры: -// ПостфиксСобытия - Строка - Может быть пустым -// Текст - - -// -&НаСервереБезКонтекста -Функция ЗаписатьПримечаниеВЖурналРегистрации(Знач Текст, ПостфиксСобытия = "") - ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); // эта пляска для случаев когда ПостфиксСобытия будет пустой, что б в конце не осталась точка - ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), УровеньЖурналаРегистрации.Примечание,,, Текст); - - Возврат Текст; -КонецФункции - -&НаСервереБезКонтекста -Функция ИмяСобытияЖР() - - Возврат "VanessaADD.ТестКлиенты"; - -КонецФункции - -&НаКлиенте -Процедура ЗапомнитьДанныеТестКлиента(ТестКлиент, ИмяПользователя, Порт, ДопПараметры) - - ДанныеТестКлиента = Новый Структура; - ДанныеТестКлиента.Вставить("ТестКлиент", ТестКлиент); - ДанныеТестКлиента.Вставить("ИмяПользователя", ИмяПользователя); - ДанныеТестКлиента.Вставить("Порт", Порт); - ДанныеТестКлиента.Вставить("ДопПараметры", ДопПараметры); - - Если ЗапущенныеТестКлиенты = Неопределено Тогда - ЗапущенныеТестКлиенты = Новый Массив; - КонецЕсли; - - ЗапущенныеТестКлиенты.Добавить(ДанныеТестКлиента); - -КонецПроцедуры - -&НаКлиенте -Функция НайтиЗапущенныйКлиент(ИмяПользователя, Порт) - - Если Не ЗначениеЗаполнено(ЗапущенныеТестКлиенты) Тогда - Возврат Неопределено; - КонецЕсли; - - Для Каждого ТекЗапущенныйКлиент Из ЗапущенныеТестКлиенты Цикл - Если ТекЗапущенныйКлиент.ИмяПользователя = ИмяПользователя - И ТекЗапущенныйКлиент.Порт = Порт Тогда - Возврат ТекЗапущенныйКлиент.ТестКлиент; - КонецЕсли; - КонецЦикла; - -КонецФункции - -&НаКлиенте -Функция ПолучитьПорт(Знач Порт) - Если Не ЗначениеЗаполнено(Порт) Тогда - Порт = ПортПоУмолчанию(); - КонецЕсли; - - Если ТипЗнч(Порт) <> Тип("Число") Тогда - Порт = Число(Порт); - КонецЕсли; - - ЗаписатьИнформациюВЖурналРегистрации(СтрШаблон("Будет использован порт: ""%1""", Порт)); - Возврат Порт; -КонецФункции - -&НаКлиенте -Функция НажатьКнопкуМодальногоДиалога(Знач ОписаниеМодальногоОкна, Знач Кнопки) - Перем ИндексКнопки; - - Если Не ОписаниеМодальногоОкна.Свойство("Кнопка", ИндексКнопки) Тогда - Возврат Ложь; - КонецЕсли; - - Если ИндексКнопки = Неопределено ИЛИ ИндексКнопки < 0 Тогда - КонтекстЯдра.ВывестиСообщение("Индекс кнопки не должен быть 0 или меньше 0", СтатусСообщения.ОченьВажное); - Возврат Ложь; - КонецЕсли; - - Если ИндексКнопки >= Кнопки.Количество() Тогда - КонтекстЯдра.ВывестиСообщение("Индекс кнопки не должен быть больше количества кнопок в форме " + Кнопки.Количество(), - СтатусСообщения.ОченьВажное); - Возврат Ложь; - КонецЕсли; - - КонтекстЯдра.Отладка(" -->> НажатьКнопкуМодальногоДиалога - Индекс нажимаемой кнопки " + ИндексКнопки); - - Попытка - Кнопки[ИндексКнопки].Нажать(); - Возврат Истина; - Исключение - Инфо = ИнформацияОбОшибке(); - ОписаниеОшибки = "Ошибка нажатия на кнопку. - |" + ПодробноеПредставлениеОшибки(Инфо); - - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки, КлючНастройкиМодальныхОкон()); - - КонтекстЯдра.ВывестиСообщение("Не удалось нажать кнопку в форме", СтатусСообщения.ОченьВажное); - КонецПопытки; - - Возврат Ложь; -КонецФункции - -&НаКлиенте -Функция НажатьКнопкуМодальногоДиалогаЕслиНаФормеВсегоОднаКнопка(Знач Кнопки, Заголовок) - Если Кнопки.Количество() <> 1 Тогда - Возврат Ложь; - КонецЕсли; - - Попытка - Кнопки[0].Нажать(); - Возврат Истина - Исключение - ОписаниеОшибки = "Ошибка нажатия на кнопку. - |" + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()); - ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки, КлючНастройкиМодальныхОкон()); - - КонтекстЯдра.ВывестиСообщение("Не удалось нажать кнопку в форме " + Заголовок, - СтатусСообщения.ОченьВажное); - - Возврат Ложь; - КонецПопытки; -КонецФункции - -&НаКлиенте -Функция ДляСравнения(Знач Строка) - Возврат НРег(Строка); -КонецФункции - -&НаКлиенте -Функция НайтиПодходящееЗначениеПоКлючуВКоллекции(Знач Соответствие, Знач ПроверяемаяСтрока) - ПроверяемаяСтрока = ДляСравнения(ПроверяемаяСтрока); - Значение = Соответствие.Получить(ПроверяемаяСтрока); - Если Значение <> Неопределено Тогда - Возврат Значение; - КонецЕсли; - - Для каждого КлючЗначение Из Соответствие Цикл - СтрокаИлиШаблон = ДляСравнения(КлючЗначение.Ключ); - Если КонтекстЯдра.СтрокаСоответствуетШаблону(ПроверяемаяСтрока, СтрокаИлиШаблон) Тогда - Возврат КлючЗначение.Значение; - КонецЕсли; - КонецЦикла; - - Возврат Неопределено; -КонецФункции - -&НаКлиенте -Функция РазложитьСтрокуВМассивПодстрок(Знач Строка, Знач Разделитель = ",", - Знач ПропускатьПустыеСтроки = Неопределено) Экспорт - - Результат = Новый Массив; - - // для обеспечения обратной совместимости - Если ПропускатьПустыеСтроки = Неопределено Тогда - ПропускатьПустыеСтроки = ?(Разделитель = " ", Истина, Ложь); - Если ПустаяСтрока(Строка) Тогда - Если Разделитель = " " Тогда - Результат.Добавить(""); - КонецЕсли; - Возврат Результат; - КонецЕсли; - КонецЕсли; - - Позиция = Найти(Строка, Разделитель); - Пока Позиция > 0 Цикл - Подстрока = Лев(Строка, Позиция - 1); - Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда - Результат.Добавить(Подстрока); - КонецЕсли; - Строка = Сред(Строка, Позиция + СтрДлина(Разделитель)); - Позиция = Найти(Строка, Разделитель); - КонецЦикла; - - Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Строка) Тогда - Результат.Добавить(Строка); - КонецЕсли; - - Возврат Результат; - -КонецФункции - -&НаКлиенте -Функция СтрНачинаетсяС_(Строка, СтрокаПоиска) Экспорт - Возврат Найти(Строка, СтрокаПоиска) = 1; -КонецФункции - -/// Объединяет строки из массива в строку с разделителями. -// -// Параметры: -// Массив - Массив - массив строк которые необходимо объединить в одну строку; -// Разделитель - Строка - любой набор символов, который будет использован в качестве разделителя. -// -// Возвращаемое значение: -// Строка - строка с разделителями. -// -&НаКлиенте -Функция СтрСоединить_(Массив, Разделитель = ",") Экспорт - - Результат = ""; - - Для Индекс = 0 По Массив.ВГраница() Цикл - Подстрока = Массив[Индекс]; - - Если ТипЗнч(Подстрока) <> Тип("Строка") Тогда - Подстрока = Строка(Подстрока); - КонецЕсли; - - Если Индекс > 0 Тогда - Результат = Результат + Разделитель; - КонецЕсли; - - Результат = Результат + Подстрока; - КонецЦикла; - - Возврат Результат; -КонецФункции - -&НаКлиенте -Процедура УстановитьНастройкиМодальныхОконПоУмолчанию() - НастройкиМодальныхОкон = Новый Структура; - ЗаголовкиМодальныхОкон = Новый Соответствие; - ПоляМодальныхОкон = Новый Соответствие; - - ЗаголовкиСистемныхОкон = ЗаголовкиСистемныхОкон(); - - Описание = Новый Структура; - НастройкиМодальныхОкон.Вставить("Предприятие", Описание); - Описание.Вставить("Заголовки", ЗаголовкиСистемныхОкон); - Описание.Вставить("Кнопка", 0); - - Описание = Новый Структура; - НастройкиМодальныхОкон.Вставить("ПредупреждениеБезопасности", Описание); - Заголовки = Новый Массив; - Описание.Вставить("Заголовки", Заголовки); - Заголовки.Добавить("Предупреждение безопасности"); - Описание.Вставить("Кнопка", 0); - - Описание = Новый Структура; - НастройкиМодальныхОкон.Вставить("ИзменениеДанных", Описание); - Поля = Новый Массив; - Описание.Вставить("Поля", Поля); - Поля.Добавить("данные были изменены"); - Поля.Добавить("сохранить данные"); - Описание.Вставить("Кнопка", 1); - - Описание = Новый Структура; - НастройкиМодальныхОкон.Вставить("ДанныеБылиИзменены", Описание); - Заголовки = Новый Массив; - Описание.Вставить("Заголовки", Заголовки); - Заголовки.Добавить("Данные были изменены"); - Описание.Вставить("Кнопка", 1); - - Описание = Новый Структура; - НастройкиМодальныхОкон.Вставить("ВыборТипаДанных", Описание); - Заголовки = Новый Массив; - Описание.Вставить("Заголовки", Заголовки); - Заголовки.Добавить("Выбор типа данных"); - Описание.Вставить("Кнопка", 0); - - Описание = Новый Структура; - НастройкиМодальныхОкон.Вставить("СписокЗначений", Описание); - Заголовки = Новый Массив; - Описание.Вставить("Заголовки", Заголовки); - Заголовки.Добавить("Список значений"); - Описание.Вставить("Кнопка", 0); - - УстановитьНастройкиМодальныхОкон(НастройкиМодальныхОкон, ЗаголовкиСистемныхОкон); - -КонецПроцедуры - -&НаКлиенте -Функция ЗаголовкиСистемныхОкон() - - Результат = Новый Массив; - - Результат.Добавить("1С:Предприятие"); - Результат.Добавить("1C:Enterprise"); - - Возврат Результат; - -КонецФункции - -&НаКлиенте -Функция СведенияОЗанятыхПортах() - - Результат = Новый Структура; - Результат.Вставить("Порты", Новый Массив); - Результат.Вставить("Процессы", Новый Соответствие); - - // файл в методе не будет удаляться, т.к. в асинхронном режиме это довольно неудобно. сервер 1С удалит сам. - ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt"); // BSLLS:MissingTemporaryFileDeletion-off - - Если НЕ ЭтоLinux() Тогда - СтрокаЗапуска = "netstat -ano > """ + ИмяВременногоФайла + """ 2>&1"; - - //TODO проверить быстрое использование ВыполнитьКомандуОСБезПоказаЧерногоОкна(..., Истина, Ложь); - //ВыполнитьКомандуОСБезПоказаЧерногоОкна(ТекстКоманды, Истина, Истина); - УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); - КодОтвета = УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(СтрокаЗапуска); - - Текст = ОткрытьФайл(ИмяВременногоФайла); - Если Текст = Неопределено Тогда - Возврат Результат; - КонецЕсли; - Если КодОтвета <> 0 Тогда - Ошибка = Текст.Прочитать(); - Текст.Закрыть(); - - КонтекстЯдра.ВывестиСообщениеВЛогФайл(СтрШаблон("%1ОШИБКА: Не удалось выполнить команду ""%2"", код ответа = %3 - |Ошибка: ""%4""", Символы.ПС, СтрокаЗапуска, КодОтвета, Ошибка)); - - ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("Не удалось выполнить команду ""%1"", код ответа = %2", СтрокаЗапуска, КодОтвета)); - Возврат Результат; - КонецЕсли; - - Пока Истина Цикл - Стр = Текст.ПрочитатьСтроку(); - Если Стр = Неопределено Тогда - Прервать; - КонецЕсли; - - Если Стр = "" Тогда - Продолжить; - КонецЕсли; - - Разбивка = СтрРазделить(Стр, " ", Ложь); - Если Разбивка.Количество() <> 5 Тогда - Продолжить; - КонецЕсли; - Порт_ = Разбивка[1]; - PID = Разбивка[Разбивка.ВГраница()]; - - Порт = ""; - Для НомерСимвола = 0 По СтрДлина(Порт_) - 1 Цикл - СимволСтроки = Сред(Порт_, СтрДлина(Порт_) - НомерСимвола, 1); - Если СимволСтроки = ":" Тогда - Прервать; - КонецЕсли; - Если Найти("0123456789", СимволСтроки) > 0 Тогда - Порт = СимволСтроки + Порт; - КонецЕсли; - КонецЦикла; - - Попытка - Порт = Число(Порт); - Результат.Порты.Добавить(Порт); - Результат.Процессы.Вставить(Порт, PID); - Исключение - Продолжить; - КонецПопытки; - КонецЦикла; - - Текст.Закрыть(); - - Иначе - - СтрокаЗапуска = "ss -tuwan4p 2>/dev/null | awk '{print substr($5, index($5, "":"")+1) "" "" substr($7, index($7, ""pid="")+4)}' | grep ""[\d]+\s[\d]*"" -Po | sort | uniq > """ + ИмяВременногоФайла + """"; - УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); - УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(СтрокаЗапуска); - - Текст = ОткрытьФайл(ИмяВременногоФайла); - Если Текст = Неопределено Тогда - Возврат Результат; - КонецЕсли; - - Пока Истина Цикл - Стр = Текст.ПрочитатьСтроку(); - Если Не ЗначениеЗаполнено(Стр) Тогда - Прервать; - КонецЕсли; - - Разбивка = СтрРазделить(Стр, " ", Ложь); - Если Разбивка.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - - Порт = СокрЛП(Разбивка[0]); - Попытка - Порт = Число(Порт); - Результат.Порты.Добавить(Порт); - - Если Разбивка.Количество() = 2 Тогда - Результат.Процессы.Вставить(Порт, СокрЛП(Разбивка[1])); - КонецЕсли; - Исключение - Продолжить; - КонецПопытки; - КонецЦикла; - - Текст.Закрыть(); - КонецЕсли; - - //Для каждого СтрокаДанныеКлиентовТестирования Из ДанныеКлиентовТестирования Цикл // TODO - // Результат.Добавить(СтрокаДанныеКлиентовТестирования.ПортЗапускаТестКлиента); - //КонецЦикла; - - Возврат Результат; - -КонецФункции - -&НаКлиенте -Функция ОткрытьФайл(Знач ПутьФайла) - - Текст = Новый ЧтениеТекста; - Попытка - - Текст.Открыть(ПутьФайла, "UTF-8"); - - Исключение - - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ПолныйТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - - ПолныйТекстОшибки = СтрШаблон("Не удалось прочитать файл-результат команды получения занятых портов - |%1", ПолныйТекстОшибки); - - ЗаписатьОшибкуВЖурналеРегистрации(ПолныйТекстОшибки); - - Возврат Неопределено; - - КонецПопытки; - - Возврат Текст; - -КонецФункции - -&НаКлиенте -Функция НовоеОписаниеТестКлиента() - - Результат = Новый Структура; - Результат.Вставить("Клиент", Неопределено); - Результат.Вставить("Порт", 0); - - Возврат Результат; - -КонецФункции - -// Дополняет массив (взята типовая процедура) -// -// Параметры: -// МассивПриемник - Массив - массив, в который необходимо добавить значения. -// МассивИсточник - Массив - массив значений для заполнения. -// ТолькоУникальныеЗначения - Булево - если истина, то в массив будут включены только уникальные значения. -// -&НаКлиенте -Процедура ДополнитьМассив(МассивПриемник, Знач МассивИсточник, ТолькоУникальныеЗначения = Ложь) Экспорт - - Если ТолькоУникальныеЗначения Тогда - - УникальныеЗначения = Новый Соответствие; - - Для Каждого Значение Из МассивПриемник Цикл - УникальныеЗначения.Вставить(Значение, Истина); - КонецЦикла; - - Для Каждого Значение Из МассивИсточник Цикл - Если УникальныеЗначения[Значение] = Неопределено Тогда - МассивПриемник.Добавить(Значение); - УникальныеЗначения.Вставить(Значение, Истина); - КонецЕсли; - КонецЦикла; - - Иначе - - Для Каждого Значение Из МассивИсточник Цикл - МассивПриемник.Добавить(Значение); - КонецЦикла; - - КонецЕсли; - -КонецПроцедуры - -&НаКлиентеНаСервереБезКонтекста -Функция ЗначениеВМассиве(Значение) - Массив = Новый Массив; - Массив.Добавить(Значение); - - Возврат Массив; -КонецФункции - -&НаКлиенте -Функция ДанныеКешаПроверкиОкон(Знач ОкноПриложения) - Результат = КешПроверкиОкон.Получить(НормализоватьЗаголовокОкна(ОкноПриложения)); - Если ЗначениеЗаполнено(Результат) Тогда - Возврат Результат; - КонецЕсли; - - Возврат Новый Структура; -КонецФункции - -&НаКлиенте -Процедура ДобавитьВКешПроверкиОкон(Знач ОкноПриложения, Знач Успешно, Знач Описание) - Структура = НовыйРезультатКешаПроверкиОкон(); - Структура.Успешно = Успешно; - Структура.Описание = Описание; - КешПроверкиОкон.Вставить(НормализоватьЗаголовокОкна(ОкноПриложения), Структура); -КонецПроцедуры - -&НаКлиенте -Функция УдалитьИзКешаПроверкиОкон(Знач ОкноПриложения) - КешПроверкиОкон.Удалить(НормализоватьЗаголовокОкна(ОкноПриложения)); -КонецФункции - -&НаКлиенте -Функция НовыйРезультатКешаПроверкиОкон() - Возврат Новый Структура("Успешно, Описание", Ложь, ""); -КонецФункции - -// обертка над ПолучитьПодчиненныеОбъекты. Попытка обойти ошибку "Ошибка сетевого взаимодействия при вызове" -// -// Параметры: -// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения -// -// Возвращаемое значение: -// ФиксированныйМассив - Получает коллекцию объектов, подчиненных текущему. -// -&НаКлиенте -Функция ПодчиненныеОбъекты(ТестКлиент) - Результат = Новый Массив; - Если ТестКлиент = Неопределено Тогда - Возврат Результат; - КонецЕсли; - - Попытка - Результат = ТестКлиент.ПолучитьПодчиненныеОбъекты(); - Если Результат <> Неопределено Тогда - Возврат Результат; - КонецЕсли; - Исключение - Инфо = ИнформацияОбОшибке(); - ПОшибка = ПодробноеПредставлениеОшибки(Инфо); - - СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); - ДопСведения = Новый Массив(); - Для Каждого ТК Из ЗапущенныеТестКлиенты Цикл - ДопСведения.Добавить(СтрШаблон("Данные тест-клиента. Порт ""%1"", PID клиента ""%2""", ТК.Порт, СведенияОЗанятыхПортах.Процессы[ТК.Порт])); - КонецЦикла; - - КонтекстЯдра.ВызватьОшибкуПроверки(ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("Не удалось получить подчиненные объекты - |Количество запущенных клиентов: %1 - |СведенияОЗанятыхПортах: - | %2 - | - |Ошибка: - | %3", ЗапущенныеТестКлиенты.Количество(), СтрСоединить(ДопСведения, Символы.ПС), ПОшибка))); - - КонецПопытки; - - Возврат Результат; -КонецФункции - -&НаКлиентеНаСервереБезКонтекста -Функция МассивСодержит(Массив, Элемент) - - Если ТипЗнч(Массив) <> Тип("Массив") Тогда - Возврат Ложь; - КонецЕсли; - - Для Каждого М Из Массив Цикл - Если СтрНайти(Элемент, М) > 0 ИЛИ СтрНайти(М, Элемент) > 0 Тогда // где-то может стоять точка в конце, где-то нет. - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; -КонецФункции - -// } Helpers +&НаКлиенте +Перем ЗапущенныеТестКлиенты; + +&НаКлиенте +Перем КонтекстЯдра; + +&НаКлиенте +Перем ПортПоУмолчанию; + +&НаКлиенте +Перем НастройкиМодальныхОкон; + +&НаКлиенте +Перем ЗаголовкиМодальныхОкон; + +&НаКлиенте +Перем ПоляМодальныхОкон; + +&НаКлиенте +Перем СписокПропускаемыхФорм; + +&НаКлиенте +Перем КешПроверкиОкон; + +// { Plugin interface +&НаКлиенте +Функция ОписаниеПлагина(КонтекстЯдра, ВозможныеТипыПлагинов) Экспорт + Возврат ОписаниеПлагинаНаСервере(ВозможныеТипыПлагинов); +КонецФункции + +&НаСервере +Функция ОписаниеПлагинаНаСервере(ВозможныеТипыПлагинов) + КонтекстЯдраНаСервере = ВнешниеОбработки.Создать("xddTestRunner"); + Возврат ЭтотОбъектНаСервере().ОписаниеПлагина(КонтекстЯдраНаСервере, ВозможныеТипыПлагинов); +КонецФункции + +&НаКлиенте +Процедура Инициализация(КонтекстЯдраПараметр) Экспорт + КонтекстЯдра = КонтекстЯдраПараметр; + УстановитьНастройкиМодальныхОконПоУмолчанию(); +КонецПроцедуры + +&НаКлиенте +Функция ПортПоУмолчанию() Экспорт + Если Не ЗначениеЗаполнено(ПортПоУмолчанию) Тогда + УстановитьПортПоУмолчанию(49538); + КонецЕсли; + Возврат ПортПоУмолчанию; +КонецФункции + +&НаКлиенте +Процедура УстановитьПортПоУмолчанию(Знач Порт) Экспорт + ПортПоУмолчанию = Порт; +КонецПроцедуры + +&НаКлиенте +Процедура ПодключитьТестКлиент_ПакетныйРежим(Параметры_xddTestClient, ДопПараметры = Неопределено) Экспорт + ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка("ПодключитьТестКлиент: Подключаем тест-клиент пакетный режим")); + + Если ЗначениеЗаполнено(Параметры_xddTestClient) И ТипЗнч(Параметры_xddTestClient[0]) <> Тип("ФиксированныйМассив") + Тогда + НовыйМассивПараметров = Новый Массив; + НовыйМассивПараметров.Добавить(Параметры_xddTestClient); + Параметры_xddTestClient = НовыйМассивПараметров; + КонецЕсли; + + Если Не ЗначениеЗаполнено(ДопПараметры) Тогда + ДопПараметры = ""; + Иначе + ДопПараметры = ДопПараметры[0]; + КонецЕсли; + + Для Каждого ОчередныеПараметры Из Параметры_xddTestClient Цикл + Попытка + ПользовательПарольПорт = РазложитьСтрокуВМассивПодстрок(ОчередныеПараметры[0], ":"); + Если ПользовательПарольПорт.Количество() = 3 Тогда + ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("ПодключитьТестКлиент: параметры %1", + СтрСоединить(ПользовательПарольПорт, ":")))); + + ОписаниеТестКлиента = ПодключитьТестКлиент( + ПользовательПарольПорт[0], + ПользовательПарольПорт[1], + ПользовательПарольПорт[2], + ДопПараметры); + ТестКлиент = ОписаниеТестКлиента.Клиент; + + ЗапомнитьДанныеТестКлиента(ТестКлиент, ПользовательПарольПорт[0], ОписаниеТестКлиента.Порт, + ДопПараметры); + Иначе + ОписаниеТестКлиента = ПодключитьТестКлиент("", "", 0, ДопПараметры); + ТестКлиент = ОписаниеТестКлиента.Клиент; + + ЗапомнитьДанныеТестКлиента(ТестКлиент, "", ОписаниеТестКлиента.Порт, ДопПараметры); + КонецЕсли; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = "Ошибка подключения тест-клиента в пакетном режиме. + |" + ПодробноеПредставлениеОшибки(Инфо); + + ВызватьИсключение ЗаписатьОшибкуВЖурналеРегистрации(КонтекстЯдра.Отладка(ОписаниеОшибки)); + //Сообщить(ОписаниеОшибки, СтатусСообщения.ОченьВажное); // для кого сообщить, если ПакетныйРежим? + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Подключить тест-клиент +// +// Параметры: +// ИмяПользователя - Строка - имя\логин пользователя +// Пароль - Строка - пароль пользователя +// Порт - Число - порт подключения. Порт может быть изменен. +// ДопПараметры - Произвольный - доп.параметры, которые допустимы на клиенте +// +// Возвращаемое значение: +// Структура - описание тест-клиента, если удалось подключить, или Неопределено +// * Клиент - ТестируемоеПриложение, Неопределено - тестовый клиент, если удалось подключиться +// * Порт - Число - порт подключения. Совпадет с переданным, если порт был не занят, и выдается новый, если исходный порт был занят +// +&НаКлиенте +Функция ПодключитьТестКлиент(Знач ИмяПользователя = "", Знач Пароль = "", Знач Порт = 0, Знач ДопПараметры = "") Экспорт + Перем ПодключенныйТестКлиент; + + ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("ПодключитьТестКлиент: + |ИмяПользователя: %1 + |Пароль: %2 + |Порт: %3 + |ДопПараметры: %4", ИмяПользователя, Пароль, Порт, ДопПараметры))); + + Результат = НовоеОписаниеТестКлиента(); + + Порт = ПолучитьПорт(Порт); + Порт = НайтиСвободныйПортЕслиТекущийЗанят(Порт); + + Если Не ЗначениеЗаполнено(СписокПропускаемыхФорм) Тогда + СписокПропускаемыхФорм = Новый СписокЗначений; + КонецЕсли; + КешПроверкиОкон = Новый Соответствие; + + ПодключенныйТестКлиент = Неопределено; + + Попытка + Выполнить "ПодключенныйТестКлиент = Новый ТестируемоеПриложение(, XMLСтрока(Порт));"; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = "Ошибка подключения тест-клиента по порту " + Порт + " + |" + ПодробноеПредставлениеОшибки(Инфо); + + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); + КонтекстЯдра.Отладка("ПодключитьТестКлиент: ОШИБКА: + | "+ОписаниеОшибки); + + ПодключенныйТестКлиент = Неопределено; + КонецПопытки; + + Если ПодключенныйТестКлиент = Неопределено Тогда + ВызватьИсключение КонтекстЯдра.Отладка("Не удалось создать объект ТестируемоеПриложение. + |Возможно, что 1С:Предприятие 8 не было запущено в режиме Менеджера тестирования (ключ командной строки /TESTMANAGER) + |При запуске Предприятия через Конфигуратор можно включить этот режим в параметрах конфигуратора Сервис -> Параметры -> Запуск 1С:Предприятия -> Дополнительные -> Автоматизированное тестирование -> пункт ""Запускать как менеджер тестирования""."); + КонецЕсли; + + // Попытка подключиться к уже запущенному приложению. + Подключен = Ложь; + Попытка + ПодключенныйТестКлиент.УстановитьСоединение(); + Подключен = Истина; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = "Ошибка соединения с тест-клиентом. Порт " + Порт + " + |" + ПодробноеПредставлениеОшибки(Инфо); + + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); + КонтекстЯдра.Отладка("ПодключитьТестКлиент: ОШИБКА: + | "+ОписаниеОшибки); + + Подключен = Ложь; + КонецПопытки; + + Если Подключен Тогда + Результат.Вставить("Клиент", ПодключенныйТестКлиент); + Результат.Вставить("Порт", Порт); + + СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); + ЗаписатьИнформациюВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("Тест-клиент подключен успешно. Порт ""%1"", PID клиента ""%2""", Порт, СведенияОЗанятыхПортах.Процессы[Порт]))); + Возврат Результат; + КонецЕсли; + + СтрокаЗапуска = СтрокаЗапускаТестКлиента(ИмяПользователя, Пароль, Порт, ДопПараметры); + + УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); + УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(СтрокаЗапуска, Ложь, Ложь); + + ВремяОкончанияОжидания = ТекущаяДата() + ТаймаутВСекундах(); + ОписаниеОшибкиСоединения = ""; + СчетчикПопыток = 0; + Пока Не ТекущаяДата() >= ВремяОкончанияОжидания Цикл + Попытка + СчетчикПопыток = СчетчикПопыток + 1; + + Если Не ТестКлиентЗапущен(Порт) Тогда + ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("Не запущен процесс тест-клиента на порту %1", Порт)); + Прервать; + КонецЕсли; + + ПодключенныйТестКлиент.УстановитьСоединение(); + Подключен = Истина; + Прервать; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = СтрШаблон("Попытка %1. Ошибка подключения тест-клиента. Порт %2 + |%3", СчетчикПопыток, Порт, ПодробноеПредставлениеОшибки(Инфо)); + + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); + КонтекстЯдра.Отладка("ПодключитьТестКлиент: " + ОписаниеОшибки); + КонецПопытки; + КонецЦикла; + + Если Не Подключен Тогда + ВызватьИсключение КонтекстЯдра.Отладка(СтрШаблон( + "ПодключитьТестКлиент: Не смогли установить соединение с тестовым приложением для пользователя %1! + |%2", + ИмяПользователя, ОписаниеОшибкиСоединения)); + КонецЕсли; + + СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); + Если Подключен И ОсновноеОкно(ПодключенныйТестКлиент) = Неопределено Тогда + Таймаут = 5; + ДлительностьОжидания = 0; + Попытка + Пока ОсновноеОкно(ПодключенныйТестКлиент) = Неопределено И ДлительностьОжидания < ТаймаутВСекундах() Цикл + ПодключенныйТестКлиент.ПолучитьАктивноеОкно().Активизировать(); + ДлительностьОжидания = ДлительностьОжидания + Таймаут; + + Пауза(ПодключенныйТестКлиент, Таймаут); + КонецЦикла; + + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ОписаниеОшибкиСоединения = КраткоеПредставлениеОшибки(ИнформацияОбОшибке); + ПолныйТекстСообщения = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + + ЗаписатьПредупреждениеВЖурналРегистрации(ПолныйТекстСообщения); + + ВызватьИсключение КонтекстЯдра.Отладка(СтрШаблон( + "ru = 'ПодключитьТестКлиент: Не смогли получить основное окно тестового приложения (пользователь %1) + |%2!", ИмяПользователя, ОписаниеОшибкиСоединения)); + + КонецПопытки; + Если ОсновноеОкно(ПодключенныйТестКлиент) = Неопределено Тогда + ПодключенныйТестКлиент.НайтиОбъект(Тип("ТестируемаяКнопкаФормы"), "Отмена").Нажать(); + ПодключенныйТестКлиент.РазорватьСоединение(); + + ВызватьИсключение ЗаписатьОшибкуВЖурналеРегистрации(КонтекстЯдра.Отладка(НСтр("ru = 'ПодключитьТестКлиент: Превышено время ожидания ввода пароля.'"))); + КонецЕсли; + КонецЕсли; + + Результат.Вставить("Клиент", ПодключенныйТестКлиент); + Результат.Вставить("Порт", Порт); + + ЗаписатьИнформациюВЖурналРегистрации(КонтекстЯдра.Отладка(СтрШаблон("ПодключитьТестКлиент: Тест-клиент подключен успешно. Порт ""%1"", PID клиента ""%2""", Порт, СведенияОЗанятыхПортах.Процессы[Порт]))); + + Возврат Результат; + +КонецФункции + +&НаКлиенте +Процедура ЗавершитьВсеТестКлиенты() Экспорт + + КонтекстЯдра.Отладка("Перед завершением всех тест-клиентов"); + + Если Не ЗначениеЗаполнено(ЗапущенныеТестКлиенты) Тогда + + КонтекстЯдра.Отладка(" - Не найдено запущенных тест-клиентов"); + Возврат; + + КонецЕсли; + + Для Каждого ТекЗначение Из ЗапущенныеТестКлиенты Цикл + + Порт = XMLСтрока(ТекЗначение.Порт); + КонтекстЯдра.Отладка(" - Нашли тест-клиент. Порт " + Порт); + + Если ЭтоLinux() Тогда + ЗапуститьПриложение("kill -9 `ps aux | grep -ie TESTCLIENT | grep -ie 1cv8c | awk '{print $2}'`"); + Иначе + ТекстСкрипта = ТекстСкриптаЗавершитьТестКлиент(Порт); + КонтекстЯдра.Отладка(" - текст скрипта удаления. " + ТекстСкрипта); + + КодВозврата = Неопределено; + ЗапуститьПриложение("cmd /c" + ТекстСкрипта,, Истина, КодВозврата); + Если ЗначениеЗаполнено(КодВозврата) Тогда + КонтекстЯдра.Отладка(СтрШаблон(" - После запуска команды завершения тест-клиента. КодВозврата: %1, Порт %2", КодВозврата, Порт)); + Иначе + КонтекстЯдра.Отладка(" - После запуска команды завершения тест-клиента. Порт " + Порт); + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +&НаКлиенте +Функция ТестКлиентЗапущен(Порт) + + Результат = Ложь; + ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt"); // BSLLS:MissingTemporaryFileDeletion-off + + ЭтоLinux = ЭтоLinux(); + + П = XMLСтрока(Порт); + Если ЭтоLinux Тогда + ЗапуститьПриложение(СтрШаблон("ps aux | grep -ie TESTCLIENT | grep -ie 1cv8c | grep ""TPort[\s]*%1"" -iP > %2", П, ИмяВременногоФайла), , Истина); + Иначе + ТекстСкрипта = СтрЗаменить(ТекстСкриптаИнформацияОЗапущенныхКлиентах(П), "%", "%%") + " > " + ИмяВременногоФайла; + УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); + КодОтвета = УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(ТекстСкрипта, Истина); + КонецЕсли; + + Попытка + + Текст = Новый ЧтениеТекста(ИмяВременногоФайла, "UTF-8"); + КоличествоСтрок = СтрЧислоСтрок(Текст.Прочитать()); + + Результат = КоличествоСтрок > 0; + + Текст.Закрыть(); + + Исключение + + // стандарт по исключениям https://its.1c.ru/db/v8std/content/499/hdoc + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ЗаписатьПредупреждениеВЖурналРегистрации("Не прочитали файл + |" + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке), "ТестКлиентЗапущен"); + + Результат = Ложь; + КонецПопытки; + + Возврат Результат; +КонецФункции + +// Получить последнее (по порядку) открытое окно +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение +// +// Возвращаемое значение: +// ТестируемоеОкноКлиентскогоПриложения +// +&НаКлиенте +Функция ПервоеОкноИзСтека(ТестКлиент) Экспорт + ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); + Если ЗначениеЗаполнено(ОткрытыеОкна) Тогда + Возврат ОткрытыеОкна[0]; + КонецЕсли; + + Возврат Неопределено; +КонецФункции + +&НаКлиенте +Функция ТестКлиентПоУмолчанию() Экспорт + + Если ЗначениеЗаполнено(ЗапущенныеТестКлиенты) Тогда + Текст = СтрШаблон("ПодключитьТестКлиент: Был использован один из запущенных ранее тест-клиентов. + | ИмяПользователя: %1 + | Порт: %2 + | ДопПараметры: %3", ЗапущенныеТестКлиенты[0].ИмяПользователя, + ЗапущенныеТестКлиенты[0].Порт, + ЗапущенныеТестКлиенты[0].ДопПараметры); + + ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(Текст)); + Возврат ЗапущенныеТестКлиенты[0].ТестКлиент; + КонецЕсли; + + ОписаниеТестКлиента = ПодключитьТестКлиент(); + Результат = ОписаниеТестКлиента.Клиент; + + ЗапомнитьДанныеТестКлиента(Результат, "", ОписаниеТестКлиента.Порт, ""); + + Текст = СтрШаблон("ПодключитьТестКлиент: Был запущен новый тест-клиент. + | Порт: %1", ОписаниеТестКлиента.Порт); + ЗаписатьПримечаниеВЖурналРегистрации(КонтекстЯдра.Отладка(Текст)); + + Возврат Результат; +КонецФункции + +&НаКлиенте +Функция ТестКлиентПоПараметрам(Знач ИмяПользователя = "", Знач Пароль = "", Знач Порт = 0, + Знач ДопПараметры = "") Экспорт + Порт = ПолучитьПорт(Порт); + + Результат = НайтиЗапущенныйКлиент(ИмяПользователя, Порт); + Если Результат <> Неопределено Тогда + Возврат Результат; + КонецЕсли; + + ОписаниеТестКлиента = ПодключитьТестКлиент(ИмяПользователя, Пароль, Порт, ДопПараметры); + Результат = ОписаниеТестКлиента.Клиент; + + ЗапомнитьДанныеТестКлиента(Результат, ИмяПользователя, ОписаниеТестКлиента.Порт, ДопПараметры); + + Возврат Результат; + +КонецФункции + +// Идентифицировать окно предупреждение +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения +// Пояснение - Строка - Доп информация для вывода в содержимое ошибки +// ИгнорируемыйМассивТекстовИсключений - Массив, Неопределено - Массив строк содержащий исключения для игнорирования +// ОкнаДо - Соответствие - открытые окна до проверки. на их основе вычисляются новые открытые окна, чтобы не перебирать все окна тест-клиента. Важно для ускорения! +// +&НаКлиенте +Процедура ИдентифицироватьОкноПредупреждение(Знач ТестКлиент, Знач Пояснение = "", ИгнорируемыйМассивТекстовИсключений = Неопределено, + Знач ОкнаДо = Неопределено) Экспорт + + // 1. проверяем наличие ошибки + ТекущаяИнформацияОбОшибке = ТестКлиент.ПолучитьТекущуюИнформациюОбОшибке(); + Если ТипЗнч(ТекущаяИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда + ПодробноеПредставлениеОшибки = ПодробноеПредставлениеОшибки(ТекущаяИнформацияОбОшибке); + КраткоеПредставление = КраткоеПредставлениеОшибки(ТекущаяИнформацияОбОшибке); + + Если ИгнорируемыйМассивТекстовИсключений <> Неопределено И МассивСодержит(ИгнорируемыйМассивТекстовИсключений, КраткоеПредставление) Тогда + ПодробноеПредставлениеОшибки = ""; + КонтекстЯдра.Отладка(СтрШаблон("ОКНА: Пропустили исключение при открытии окна. + | Текст ошибки: ""%1""", КраткоеПредставление)); + Иначе + ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("ИдентифицироватьОкноПредупреждение выявило ошибку: + |""%1""", ПодробноеПредставлениеОшибки), КлючНастройкиМодальныхОкон()); + КонецЕсли; + + Если ЗначениеЗаполнено(ПодробноеПредставлениеОшибки) Тогда // могут быть исключения для ошибок + ЗакрытьВсеОткрытыеОкна(ТестКлиент); + КонтекстЯдра.ВызватьОшибкуПроверки(СтрШаблон("Выявлена ошибка: ""%1""", ПодробноеПредставлениеОшибки)); + Иначе + НажатьОК(ТестКлиент); + КонецЕсли; + Иначе + Ошибка = ТекстСистемногоОкнаОшибки(ТестКлиент, ОкнаДо); + Если ЗначениеЗаполнено(Ошибка) Тогда + Если Не ЗначениеЗаполнено(ИгнорируемыйМассивТекстовИсключений) ИЛИ Не МассивСодержит(ИгнорируемыйМассивТекстовИсключений, Ошибка) Тогда + ЗакрытьВсеОткрытыеОкна(ТестКлиент); + КонтекстЯдра.ВызватьОшибкуПроверки(СтрШаблон("Выявлено окно с ошибкой: ""%1""", Ошибка)); + Иначе + НажатьОК(ТестКлиент); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + // при совершении различных действий тестом (открытие формы, клик по кнопке) может появиться окно длительной операции + // если оно открыто, ждем n секунд, пока не закроется. если не закроется, выдается ошибка + ОкноДлительныхОпераций = ОкноДлительныхОпераций(ТестКлиент); + Если ОкноДлительныхОпераций <> Неопределено И Не ОкноДлительныхОпераций.ОжидатьЗакрытие(15) Тогда + КонтекстЯдра.ВызватьОшибкуПроверки("Тест прерван. Не дождались закрытия окна длительных операций"); + КонецЕсли; + + // 2. Проверяем наличие новых окон, пробуем их закрыть (просто закрыть, модальные в соответствии с настройками) + // закрыть все окна было бы неверно, т.к. могут быть случаи, когда открыли форму объекта и в этой форме выполняем различные действия (кликаем по строкам, переходим по ком. интерфейсу) + // такое поведение есть в тесты_КомандныйИнтерфейс, и нужно закрывать только те окна, которые появились после выполняемых действий, форму объекта не должны трогать + СписокПропускаемыхФорм.Очистить(); + ЗакрытьВсеОткрытыеОкнаСУчетомНастроек(ТестКлиент, ОкнаДо); +КонецПроцедуры + +// не все ошибки ловятся через ТестКлиент.ПолучитьТекущуюИнформациюОбОшибке(), например ошибки дин. списка так не поймать +// у таких ошибок ИмяФормы ErrorWindow +&НаКлиенте +Функция ТекстСистемногоОкнаОшибки(Знач ТестКлиент, Знач ОкнаДо) + + Если ЗначениеЗаполнено(ОкнаДо) Тогда + НовыеОткрытыеОкна = НовыеОткрытыеОкна(ТестКлиент, ОкнаДо); + ОткрытыеОкна = МассивОткрытыхОкон(НовыеОткрытыеОкна); + Иначе + ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); + КонецЕсли; + Для Каждого ТекОкно Из ОткрытыеОкна Цикл + Объекты = ТекОкно.ПолучитьПодчиненныеОбъекты(); + Для Каждого ОбъектОкна Из Объекты Цикл + // Заголовок "1С:Предприятие" + Если Тип(ОбъектОкна) = Тип("ТестируемаяФорма") И ОбъектОкна.ИмяФормы = "ErrorWindow" Тогда + Возврат СодержимоеОкна(ТекОкно) + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Возврат ""; +КонецФункции + +&НаКлиенте +Функция ПоявилосьОкноПредупрежденияСТекстом(Знач ТестКлиент, Знач ТекстИсключенияДляПроверки, Знач ОкнаДо) Экспорт + Перем ОкноПредупреждение; + + //ПодчиненныеОбъекты = ПодчиненныеОбъекты(ТестКлиент); + //Для Каждого ПодчиненныйОбъект Из ПодчиненныеОбъекты Цикл + ВсеОткрытыеОкна = ОткрытыеОкнаИзМассиваОкон(ПодчиненныеОбъекты(ТестКлиент)); + ОткрытыеОкна = ИсключитьРанееОткрытыеОкна(ВсеОткрытыеОкна, ОкнаДо); + + Для Каждого КлючЗначение Из ОткрытыеОкна Цикл + ПодчиненныйОбъект = КлючЗначение.Значение; + Если ТипЗнч(ПодчиненныйОбъект) <> Тип("ТестируемоеОкноКлиентскогоПриложения") Тогда + Продолжить; + КонецЕсли; + Если ПодчиненныйОбъект.Основное Или ПодчиненныйОбъект.НачальнаяСтраница Тогда + Продолжить; + КонецЕсли; + + Если НайтиОписаниеМодальногоОкна(ПодчиненныйОбъект) <> Неопределено Тогда + ОкноПредупреждение = ПодчиненныйОбъект; + Прервать; + КонецЕсли; + КонецЦикла; + + ТекстИсключения = СодержимоеОкна(ОкноПредупреждение); // проверка на неопределено внутри + + Возврат ЗначениеЗаполнено(ТекстИсключения) И Найти(ВРег(ТекстИсключения), ВРег(ТекстИсключенияДляПроверки)) > 0; +КонецФункции + +&НаКлиенте +Процедура НажатьОК(ТестКлиент) + ОкноОшибки = ПервоеОкноИзСтека(ТестКлиент); + Если ОкноОшибки = Неопределено Тогда + Возврат; + КонецЕсли; + + Кнопки = ПолучитьКнопки(ОкноОшибки); + Для Каждого Кнопка Из Кнопки Цикл + Если ВРег(Кнопка.Имя) = "OK" ИЛИ ВРег(Кнопка.Имя) = "ОК" Тогда // латиница и кириллица + Кнопка.Нажать(); + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +&НаКлиенте +Функция НайтиОписаниеМодальногоОкна(ОкноПриложения) + Перем Поля; + + Если КонтекстЯдра.ОтладкаВключена() Тогда + КонтекстЯдра.Отладка(СтрШаблон(" -->> НайтиОписаниеМодальногоОкна - заголовок окна %1, %2", + ОкноПриложения.Заголовок, СодержимоеОкна(ОкноПриложения))); + КонецЕсли; + + // Если в настройках задан заголовок и поля, отбор по "И" + // если на этом этапе ОписаниеМодальногоОкна = неопределено, значит, нет подходящего описания для заголовка + // возможно, в описании заданы только поля, а заголовка нет, тогда ищем по полям. ОписаниеМодальногоОкна <> неопределено, мы должны проверить поля именно этого описания + // если проверять по ПоляМодальныхОкон, можно получить ситуацию, когда заголовок из одной настройки, а поля из другой. + + // НайтиПодходящееЗначениеПоКлючуВКоллекции должен возвращать массив, т.к. для обеспечения указанной логики работы может быть несколько правил (описаний) + // с одним и тем же заголовком, но разными полями и разными кнопками. Т.е. поля - это способ уточнить поиск окна, заголовок первичнее + ОписанияМодальногоОкна = НайтиПодходящееЗначениеПоКлючуВКоллекции(ЗаголовкиМодальныхОкон, ОкноПриложения.Заголовок); + + Если ОписанияМодальногоОкна = Неопределено ИЛИ ОписанияМодальногоОкна.Количество() = 0 Тогда + + Если Не ЗначениеЗаполнено(ПоляМодальныхОкон) Тогда + Возврат Неопределено; + КонецЕсли; + РанееПроверенныеРезультаты = ДанныеКешаПроверкиОкон(ОкноПриложения); + Если ЗначениеЗаполнено(РанееПроверенныеРезультаты) Тогда + Возврат РанееПроверенныеРезультаты.Описание; + КонецЕсли; + + ПоляФормы = ОкноПриложения.НайтиОбъекты(Тип("ТестируемоеПолеФормы")); + РезультатПоиска = НайтиОписаниеМодальногоОкнаДляПолейФормы(ПоляФормы, ПоляМодальныхОкон); + Если РезультатПоиска.Успешно Тогда + ДобавитьВКешПроверкиОкон(ОкноПриложения, Истина, РезультатПоиска.Описание); + Возврат РезультатПоиска.Описание; + КонецЕсли; + + ПоляФормы = ОкноПриложения.НайтиОбъекты(Тип("ТестируемаяДекорацияФормы")); + РезультатПоиска = НайтиОписаниеМодальногоОкнаДляПолейФормы(ПоляФормы, ПоляМодальныхОкон); + Если РезультатПоиска.Успешно Тогда + ДобавитьВКешПроверкиОкон(ОкноПриложения, Истина, РезультатПоиска.Описание); + Возврат РезультатПоиска.Описание; + КонецЕсли; + + ДобавитьВКешПроверкиОкон(ОкноПриложения, Ложь, Неопределено); + Возврат Неопределено; + + КонецЕсли; + + Если ЗначениеЗаполнено(ОписанияМодальногоОкна) Тогда + ПоляФормы = Неопределено; + + // отбор правил с заголовком и с полями + Для Каждого Описание Из ОписанияМодальногоОкна Цикл + Если Не Описание.Свойство("Поля", Поля) Тогда + Продолжить; + КонецЕсли; + + Если ПоляФормы = Неопределено Тогда + ПоляФормы = Новый Массив(); + ДополнитьМассив(ПоляФормы, ОкноПриложения.НайтиОбъекты(Тип("ТестируемоеПолеФормы"))); + ДополнитьМассив(ПоляФормы, ОкноПриложения.НайтиОбъекты(Тип("ТестируемаяДекорацияФормы"))); + КонецЕсли; + + Для Каждого ТекстПоля Из Поля Цикл + ТекстПоляДляСравнения = ДляСравнения(ТекстПоля); + Для Каждого ТекПолеФормы Из ПоляФормы Цикл + Если КонтекстЯдра.СтрокаСоответствуетШаблону(ДляСравнения(ТекПолеФормы.ТекстЗаголовка), ТекстПоляДляСравнения) Тогда + Возврат Описание; + КонецЕсли; + КонецЦикла; + КонецЦикла; + КонецЦикла; + + // отбор правил без полей, но с заголовком + // если не нашли подходящее описание по полям, вернем первое подходящее без полей только с заголовком + Для Каждого Описание Из ОписанияМодальногоОкна Цикл + Если Не Описание.Свойство("Поля", Поля) Тогда + Возврат Описание; + КонецЕсли; + КонецЦикла; + + КонецЕсли; + + Возврат Неопределено; +КонецФункции + +&НаКлиенте +Функция НайтиОписаниеМодальногоОкнаДляПолейФормы(ПоляФормы, ПоляМодальныхОкон) + + Результат = Новый Структура("Успешно, Описание", Ложь, Неопределено); + + // отбор правил без заголовка, но с полями + Для Каждого ТекПолеФормы Из ПоляФормы Цикл + Настройки = НайтиПодходящееЗначениеПоКлючуВКоллекции(ПоляМодальныхОкон, ТекПолеФормы.ТекстЗаголовка); + Если Настройки = Неопределено Тогда + Продолжить; + КонецЕсли; + + Для Каждого Описание Из Настройки Цикл + // интересуют те описания, у которых нет заголовка, по заголовку поиск выше + Если Не Описание.Свойство("Заголовки") Тогда + Результат.Успешно = Истина; + Результат.Описание = Описание; + Возврат Результат; + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Возврат Результат; +КонецФункции + +&НаКлиенте +// Возвращает основное окно текущего тест-клиента +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение - ТестируемоеПриложение +// +// Возвращаемое значение: +// ТестируемоеОкноКлиентскогоПриложения - или Неопределено, если не нашли или ошибка сетевого взаимодействия +// +Функция ОсновноеОкно(ТестКлиент) Экспорт + Попытка + КлиентскиеОкнаТестируемогоПриложения = ПодчиненныеОбъекты(ТестКлиент); + Для Каждого ТекОкно Из КлиентскиеОкнаТестируемогоПриложения Цикл + Если ТекОкно.Основное Тогда + Возврат ТекОкно; + КонецЕсли; + КонецЦикла; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = "Ошибка поиска основного окна тест-клиента. + |" + ПодробноеПредставлениеОшибки(Инфо); + + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); + + Возврат Неопределено; + КонецПопытки; + + Возврат Неопределено; +КонецФункции + +&НаКлиенте +Процедура Пауза(ТестКлиент, КоличествоСекунд) Экспорт + + ТестКлиент.ОжидатьОтображениеОбъекта(Тип("ТестируемаяФорма"), "ЗаведомоОтсутствующийОбъект",, КоличествоСекунд); + +КонецПроцедуры + +&НаКлиенте +Функция СодержимоеОкна(ОкноПредупреждение) Экспорт + Перем Содержимое; + + Если ОкноПредупреждение = Неопределено Тогда + Возврат ""; + КонецЕсли; + + Для Каждого ТекДекорацияФормы Из ОкноПредупреждение.НайтиОбъекты(Тип("ТестируемаяДекорацияФормы")) Цикл + Если ТекДекорацияФормы.Имя = "Message" Тогда + Содержимое = ТекДекорацияФормы.ТекстЗаголовка; + ИначеЕсли ТекДекорацияФормы.Имя = "ErrorInfo" Тогда + Содержимое = ТекДекорацияФормы.ТекстЗаголовка; + КонецЕсли; + КонецЦикла; + + Если Содержимое = Неопределено Тогда + ТекстыЗаголовков = Новый Массив; + Для Каждого ТекПолеФормы Из ОкноПредупреждение.НайтиОбъекты(Тип("ТестируемоеПолеФормы")) Цикл + Если ЗначениеЗаполнено(ТекПолеФормы.ТекстЗаголовка) Тогда + ТекстыЗаголовков.Добавить(ТекПолеФормы.ТекстЗаголовка); + КонецЕсли; + КонецЦикла; + Содержимое = УкоротитьСтроку(СтрСоединить(ТекстыЗаголовков, ", "), 100); + КонецЕсли; + + Возврат СтрШаблон("Заголовок: <%1>; Содержимое: <%2>", ОкноПредупреждение.Заголовок, Содержимое); +КонецФункции + +&НаКлиенте +Функция УкоротитьСтроку(Знач Стр, Длина) + Стр2 = Лев(Стр, Длина); // нет смысла выводить длинную портянку + Возврат ?(СтрДлина(Стр2) < СтрДлина(Стр), Стр2+"...", Стр2); +КонецФункции + +// Возвращает заголовок и содержимое открытых окон +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения - +// +// Возвращаемое значение: +// Строка - Строка разделенная переносом строк, каждая строчка это представление окна +// +&НаКлиенте +Функция ПредставленияОткрытыхОкон(ТестКлиент) Экспорт + ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); + ОписанияОкон = Новый Массив(); + Для а = 0 По ОткрытыеОкна.ВГраница() Цикл + Если ОткрытыеОкна[а].Основное ИЛИ ОткрытыеОкна[а].НачальнаяСтраница + ИЛИ ТипЗнч(ОткрытыеОкна[а]) <> Тип("ТестируемоеОкноКлиентскогоПриложения") Тогда + Продолжить; + КонецЕсли; + + ОписанияОкон.Добавить(СтрШаблон("[%1] %2", а, СодержимоеОкна(ОткрытыеОкна[а]))); + КонецЦикла; + + Возврат СтрСоединить(ОписанияОкон, Символы.ПС); +КонецФункции + +&НаКлиенте +Процедура ЗакрытьВсеОткрытыеОкна(ТестКлиент) Экспорт + КонтекстЯдра.Отладка("ОКНА: Закрываем все открытые окна"); + + СписокПропускаемыхФорм.Очистить(); + + ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); + Для Каждого ТекОкно Из ОткрытыеОкна Цикл + //Если ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда + // Продолжить; + //КонецЕсли; + Если ПропуститьОкно(ТекОкно) Тогда + КонтекстЯдра.Отладка(СтрШаблон(" -->> Окно пропущено ""%1""", ТекОкно.Заголовок)); + Продолжить; + КонецЕсли; + + Попытка + ТекОкно.Закрыть(); + КонтекстЯдра.Отладка(СтрШаблон(" -->> Закрыли окно ""%1""", ТекОкно.Заголовок)); + Исключение + // Необходимо принудительно закрыть все окна, специальная обработка исключений не требуется. + СписокПропускаемыхФорм.Добавить(ТекОкно.Заголовок); + КонтекстЯдра.Отладка(СтрШаблон(" -->> Ошибка закрытия окна ""%1""", ТекОкно.Заголовок)); + КонецПопытки; + КонецЦикла; +КонецПроцедуры + +// Закрываются все открытые окна с учетом настроек +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения - +// ОкнаДо - Соответствие, Неопределено - Необязательный. +// +&НаКлиенте +Процедура ЗакрытьВсеОткрытыеОкнаСУчетомНастроек(ТестКлиент, Знач ОкнаДо = Неопределено) Экспорт + КонтекстЯдра.Отладка("ОКНА: Закрываем все новые окна с учетом настроек, ранее открытые окна не закрываем"); + + Если Не ЗначениеЗаполнено(ОкнаДо) Тогда + ОкнаДо = КонструкторОткрытыеОкна(); + КонецЕсли; + + ВсеОткрытыеОкна = ОткрытыеОкнаИзМассиваОкон(ПодчиненныеОбъекты(ТестКлиент)); + ОткрытыеОкна = ИсключитьРанееОткрытыеОкна(ВсеОткрытыеОкна, ОкнаДо); + + Для Каждого КлючЗначение Из ОткрытыеОкна Цикл + ТекОкно = КлючЗначение.Значение; + Если ПропуститьОкно(ТекОкно) + ИЛИ ТипЗнч(ТекОкно) <> Тип("ТестируемоеОкноКлиентскогоПриложения") Тогда + Продолжить; + КонецЕсли; + + Кнопки = ПолучитьКнопки(ТекОкно); + Если Не ЗначениеЗаполнено(Кнопки) Тогда + Продолжить; + КонецЕсли; + + ОписаниеМодальногоОкна = НайтиОписаниеМодальногоОкна(ТекОкно); + ОкноЗакрыто = Ложь; + Если ОписаниеМодальногоОкна = Неопределено Тогда + // много "ошибочных" кликов по кнопке на форме документа, справочника. + // Был пример где на форме кнопка "конструктор запросов" и тест на нее клиекает, что открывает конструктор и далее тест ходит по вкладкам конструктора запросов, что вообще не нужно + // лучше для окон с ошибкой или модальных задавать правила через настройки + //ОкноЗакрыто = НажатьКнопкуМодальногоДиалогаЕслиНаФормеВсегоОднаКнопка(Кнопки, ТекОкно.Заголовок); + Иначе + ОкноЗакрыто = ЗакрытьОкноПредупреждения(Кнопки, ТекОкно, ОписаниеМодальногоОкна); + КонецЕсли; + + СписокПропускаемыхФорм.Добавить(ТекОкно.Заголовок); + Если ОкноЗакрыто Тогда + КонтекстЯдра.Отладка(СтрШаблон(" -->> Закрыли окно ""%1""", ТекОкно.Заголовок)); + УдалитьИзКешаПроверкиОкон(ТекОкно); + + // успешное нажатие на кнопку может повторно открыть модальное окно, например, при закрытии формы документа появляется вопрос + // "сохранить?"" жмется "да", появляется еще окно "произвести перерасчет?" + ЗакрытьВсеОткрытыеОкнаСУчетомНастроек(ТестКлиент, ОкнаДо); + Иначе + КонтекстЯдра.Отладка(СтрШаблон(" -->> Настроек для окна ""%1"" не найдено", ТекОкно.Заголовок)); + КонецЕсли; + КонецЦикла; +КонецПроцедуры + +&НаКлиенте +Функция ОкноДлительныхОпераций(ТестКлиент) + ОткрытыеОкна = ПодчиненныеОбъекты(ТестКлиент); + Для Каждого ТекОкно Из ОткрытыеОкна Цикл + Если ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда + Продолжить; + КонецЕсли; + + Форма = ТекОкно.НайтиОбъект(Тип("ТестируемаяФорма")); + Если Форма <> Неопределено И Форма.ИмяФормы = "ОбщаяФорма.ДлительнаяОперация" Тогда + Возврат Форма; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; +КонецФункции + +&НаКлиенте +Функция ПолучитьКнопки(Окно) + Кнопки = Новый Массив(); + Попытка + Для Каждого Кнопуля Из Окно.НайтиОбъекты(Тип("ТестируемаяКнопкаФормы")) Цикл + Если Кнопуля.Вид = ВидКнопкиФормы.ОбычнаяКнопка ИЛИ Кнопуля.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели И Не СтрНачинаетсяС_(Кнопуля.ТекстЗаголовка, "Command") Тогда + Кнопки.Добавить(Кнопуля); + КонтекстЯдра.Отладка(СтрШаблон(" -->> ОКНА: %1. Кнопка ""%2"", Заголовок ""%3""", Кнопки.Количество(), Кнопуля.Имя, Кнопуля.ТекстЗаголовка)); + КонецЕсли; + КонецЦикла; + Исключение + Возврат Кнопки; + КонецПопытки; + + Возврат Кнопки; +КонецФункции + +&НаКлиенте +Функция ПропуститьОкно(ТекОкно) + + Если ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда + Возврат Истина; + КонецЕсли; + + // В массив добавляем окна, на которых уже вылезали ошибки + Если СписокПропускаемыхФорм.НайтиПоЗначению(ТекОкно.Заголовок) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; +КонецФункции + +&НаКлиенте +Функция ЗакрытьОкноПредупреждения(Кнопки, ОкноПриложения, ОписаниеМодальногоОкна) + Результат = Ложь; + + ОкноПриложения.Активизировать(); + Если ОписаниеМодальногоОкна <> Неопределено И НажатьКнопкуМодальногоДиалога(ОписаниеМодальногоОкна, Кнопки) Тогда + КонтекстЯдра.Отладка(СтрШаблон("ОКНА: Успешный клик по кнопке окна <%1>", ОкноПриложения.Заголовок)); + Результат = Истина; + Иначе + КонтекстЯдра.Отладка(СтрШаблон("ОКНА: Не удалось нажать на кнопку окна <%1>", ОкноПриложения.Заголовок)); + КонецЕсли; + + Возврат Результат; +КонецФункции + +// Возвращает открытые окна +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение - тест-клиент +// +// Возвращаемое значение: +// Соответствие - ключ - заголовок окна, символы * удалены, значение - само окно +// +&НаКлиенте +Функция ОткрытыеОкна(ТестКлиент) Экспорт + + ВсеОкна = ТестКлиент.НайтиОбъекты(Тип("ТестируемоеОкноКлиентскогоПриложения")); + + Возврат ОткрытыеОкнаИзМассиваОкон(ВсеОкна); +КонецФункции + +&НаКлиенте +Функция КонструкторОткрытыеОкна() + Возврат Новый Соответствие; +КонецФункции + +&НаКлиенте +Функция ОткрытыеОкнаИзМассиваОкон(Знач ВсеОкна) + ОткрытыеОкна = КонструкторОткрытыеОкна(); + + Для Каждого ТекОкно Из ВсеОкна Цикл + Если ТекОкно = Неопределено Или ТекОкно.Основное Или ТекОкно.НачальнаяСтраница Тогда + Продолжить; + КонецЕсли; + Заголовок = НормализоватьЗаголовокОкна(ТекОкно); + ОткрытыеОкна.Вставить(Заголовок, ТекОкно); + КонецЦикла; + + Возврат ОткрытыеОкна; +КонецФункции + +&НаКлиенте +Функция МассивОткрытыхОкон(Знач ОткрытыеОкна) + Результат = Новый Массив; + + Для Каждого КлючЗначение Из ОткрытыеОкна Цикл + Результат.Добавить(КлючЗначение.Значение); + КонецЦикла; + + Возврат Результат; +КонецФункции + +// Нормализовать заголовок окна, из заголовка удаляются хвостовые пробелы и *, +// т.к. не нужно различать, если у формы взведен флаг модифицированности +// +// Параметры: +// ТекОкно - Произвольный +// +// Возвращаемое значение: +// Строка - заголовок без хвостовых пробелов и * +// +&НаКлиенте +Функция НормализоватьЗаголовокОкна(Знач ТекОкно) Экспорт + Возврат СокрЛП(СтрЗаменить(ТекОкно.Заголовок, "*", "")); +КонецФункции + +// Возвращает новые открытые окна +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение - тест-клиент +// ОткрытыеОкнаДо - Соответствие - ранее открытые окна +// +// Возвращаемое значение: +// Соответствие - ключ - заголовок окна, символы * удалены, значение - само окно +// +&НаКлиенте +Функция НовыеОткрытыеОкна(ТестКлиент, Знач ОткрытыеОкнаДо) Экспорт + + ОткрытыеОкна = ОткрытыеОкна(ТестКлиент); + Возврат ИсключитьРанееОткрытыеОкна(ОткрытыеОкна, ОткрытыеОкнаДо); +КонецФункции + +// Возвращает только новые открытые окна, без учета уже существующих окон +// +// Параметры: +// ОткрытыеОкна - Соответствие - все открытые окна +// ОткрытыеОкнаДо - Соответствие - ранее открытые окна, которые нужно исключить из списка +// ДелатьКопиюРезультата - Булево - необязательный. Делать копию результата +// для исключения изменения исходной коллекции ОткрытыеОкна +// +// Возвращаемое значение: +// Соответствие - ключ - заголовок окна, символы * удалены, значение - само окно +// +&НаКлиенте +Функция ИсключитьРанееОткрытыеОкна(Знач ОткрытыеОкна, Знач ОткрытыеОкнаДо, Знач ДелатьКопиюРезультата = Ложь) Экспорт + + Результат = КонструкторОткрытыеОкна(); + Для каждого КлючЗначение Из ОткрытыеОкна Цикл + Результат.Вставить(КлючЗначение.Ключ, КлючЗначение.Значение); + КонецЦикла; + + Если ЗначениеЗаполнено(ОткрытыеОкнаДо) Тогда + Для Каждого КлючЗначение Из ОткрытыеОкнаДо Цикл + Результат.Удалить(КлючЗначение.Ключ); + КонецЦикла; + КонецЕсли; + + Возврат Результат; +КонецФункции + +&НаКлиенте +Процедура ПроверитьНаНовыеМодальныеОкна(ТестКлиент, ОткрытыеОкнаДо) Экспорт + Если ОткрытыеОкнаДо = Неопределено ИЛИ ТестКлиент = Неопределено Тогда + Возврат; + КонецЕсли; + + Заголовки = Новый Массив(); + НужноВыброситьИсключение = Ложь; + Попытка + ОткрытыеОкна = ТестКлиент.НайтиОбъекты(Тип("ТестируемоеОкноКлиентскогоПриложения")); + Для Каждого ТекОкно Из ОткрытыеОкна Цикл + Заголовок = НормализоватьЗаголовокОкна(ТекОкно); + + Если ТекОкно = Неопределено Или ТекОкно.Основное Или ТекОкно.НачальнаяСтраница + Или ОткрытыеОкнаДо.Получить(Заголовок) <> Неопределено Тогда + Продолжить; + КонецЕсли; + + Заголовки.Добавить(ТекОкно.Заголовок); + НужноВыброситьИсключение = Истина; + КонецЦикла; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = "Ошибка поиска основного окна тест-клиента. + |" + ПодробноеПредставлениеОшибки(Инфо); + + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки); + + КонтекстЯдра.ВывестиСообщение("Не удалось проверить модальные окна ", + СтатусСообщения.ОченьВажное); + + Возврат; + КонецПопытки; + + Если НужноВыброситьИсключение Тогда + + СодержимоеТекущегоОкна = СодержимоеОкна(ТекОкно); + ЗакрытьВсеОткрытыеОкна(ТестКлиент); + + ТекстИсключения = КонтекстЯдра.СтрШаблон_(" + |Выявлено окно, которое не закрывается! Возможно, это модальное окно. + |Текущее окно: %1 + |Открытые окна: + |%2", СодержимоеТекущегоОкна, СтрСоединить(Заголовки, Символы.Таб + Символы.ПС)); + ВызватьИсключение ТекстИсключения; + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура УстановитьНастройкиМодальныхОкон(Знач ПарамНастройкиМодальныхОкон, Знач ЗаголовкиСистемныхОкон = Неопределено) Экспорт + + Если Не ЗначениеЗаполнено(ПарамНастройкиМодальныхОкон) Тогда + Возврат; + КонецЕсли; + Если Не ЗначениеЗаполнено(ЗаголовкиСистемныхОкон) Тогда + ЗаголовкиСистемныхОкон = ЗаголовкиСистемныхОкон(); + КонецЕсли; + + Если НастройкиМодальныхОкон <> ПарамНастройкиМодальныхОкон Тогда + Для Каждого КлючЗначение Из ПарамНастройкиМодальныхОкон Цикл + НастройкиМодальныхОкон.Вставить(КлючЗначение.Ключ, КлючЗначение.Значение); + КонецЦикла; + КонецЕсли; + + ЗаголовкиМодальныхОкон = Новый Соответствие; + Для Каждого КлючЗначение Из НастройкиМодальныхОкон Цикл + Описание = КлючЗначение.Значение; + Если ТипЗнч(Описание) <> Тип("Структура") Тогда + Продолжить; + КонецЕсли; + + Заголовки = Неопределено; + Если Не Описание.Свойство("Заголовки", Заголовки) Тогда + Заголовки = ЗаголовкиСистемныхОкон; + КонецЕсли; + //Если Описание.Свойство("Заголовки", Заголовки) Тогда + Для Каждого Заголовок Из Заголовки Цикл + ЗаголовокДляСравнения = ДляСравнения(Заголовок); + Если ЗаголовкиМодальныхОкон[ЗаголовокДляСравнения] = Неопределено Тогда + ЗаголовкиМодальныхОкон[ЗаголовокДляСравнения] = Новый Массив(); + КонецЕсли; + + ЗаголовкиМодальныхОкон[ЗаголовокДляСравнения].Добавить(Описание); + КонецЦикла; + //КонецЕсли; + + Поля = Неопределено; + Если Описание.Свойство("Поля", Поля) Тогда + Для Каждого ТекстПоля Из Поля Цикл + ТекстПоляДляСравнения = ДляСравнения(ТекстПоля); + Если ПоляМодальныхОкон[ТекстПоляДляСравнения] = Неопределено Тогда + ПоляМодальныхОкон[ТекстПоляДляСравнения] = Новый Массив(); + КонецЕсли; + + ПоляМодальныхОкон[ТекстПоляДляСравнения].Добавить(Описание); + КонецЦикла; + КонецЕсли; + + КонецЦикла; + + Если КонтекстЯдра.ОтладкаВключена() Тогда + Для каждого КлючЗначение Из ЗаголовкиМодальныхОкон Цикл + ЗаголовокДляСравнения = КлючЗначение.Ключ; + Описания = КлючЗначение.Значение; + КонтекстЯдра.Отладка(СтрШаблон(" -->> ЗаголовкиМодальныхОкон - заголовок окна %1", ЗаголовокДляСравнения)); + Для каждого Описание Из Описания Цикл + Кнопка = Неопределено; + Описание.Свойство("Кнопка", Кнопка); + КонтекстЯдра.Отладка(СтрШаблон(" -->> ЗаголовкиМодальныхОкон - поле - описание.Кнопка %1", Кнопка)); + КонецЦикла; + КонецЦикла; + + Для каждого КлючЗначение Из ПоляМодальныхОкон Цикл + ТекстПоляДляСравнения = КлючЗначение.Ключ; + Описания = КлючЗначение.Значение; + КонтекстЯдра.Отладка(СтрШаблон(" -->> ПоляМодальныхОкон - текст поля %1", ТекстПоляДляСравнения)); + Для каждого Описание Из Описания Цикл + Кнопка = Неопределено; + Описание.Свойство("Кнопка", Кнопка); + КонтекстЯдра.Отладка(СтрШаблон(" -->> ПоляМодальныхОкон - поле - описание.Кнопка %1", Кнопка)); + КонецЦикла; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Функция ПолучитьНастройкиМодальныхОкон() Экспорт + Возврат НастройкиМодальныхОкон; +КонецФункции + +&НаКлиенте +Функция КлючНастройкиМодальныхОкон() Экспорт + Возврат "МодальныеОкна"; +КонецФункции + +// Найти свободный порт, если текущий\указанный порт занят другим процессом +// +// Параметры: +// Порт - Число - Необязательный. По умолчанию 1538 +// НачалоДиапазонаПортов - Число - Необязательный. По умолчанию 48000 +// ОкончаниеДиапазонаПортов - Число - Необязательный. По умолчанию 50000 +// +// Возвращаемое значение: +// Число - текущий порт или новый порт, если текущий занят +// +&НаКлиенте +Функция НайтиСвободныйПортЕслиТекущийЗанят(Знач Порт = 1538, Знач НачалоДиапазонаПортов = 48000, Знач ОкончаниеДиапазонаПортов = 50000) Экспорт + + Если Порт <= 0 Или Порт > 65536 Тогда + Порт = 1538; + КонецЕсли; + + СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); + МассивЗанятыхПортов = СведенияОЗанятыхПортах.Порты; + ПроцессыДляПортов = СведенияОЗанятыхПортах.Процессы; + + Если МассивЗанятыхПортов.Найти(Порт) <> Неопределено Тогда + Текст = СтрШаблон("Порт ""%1"" занят процессом pid: ""%2"" ", Порт, ПроцессыДляПортов[Порт]); + ЗаписатьПредупреждениеВЖурналРегистрации(Текст); + КонтекстЯдра.Отладка(Текст); + + Для СвободныйПорт = НачалоДиапазонаПортов По ОкончаниеДиапазонаПортов Цикл + Если МассивЗанятыхПортов.Найти(СвободныйПорт) = Неопределено Тогда + + Текст = СтрШаблон("Будет использован свободный порт: ""%1""", СвободныйПорт); + ЗаписатьПредупреждениеВЖурналРегистрации(Текст); + КонтекстЯдра.Отладка(Текст); + + Возврат СвободныйПорт; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат Порт; + +КонецФункции + +// } Plugin interface + +// { Helpers +&НаСервере +Функция ЭтотОбъектНаСервере() + Возврат РеквизитФормыВЗначение("Объект"); +КонецФункции + +&НаКлиенте +Функция СтрокаЗапускаТестКлиента(Знач ИмяПользователя, Знач Пароль, Знач Порт, Знач ДопПараметры) + + Если Не ЗначениеЗаполнено(ИмяПользователя) Тогда + ИмяПользователя = ИмяТекущегоПользователя(); + КонецЕсли; + + СтрокаЗапуска1с = КаталогПрограммы() + "1cv8c"; + + Если Не ЭтоLinux() Тогда + СтрокаЗапуска1с = КонтекстЯдра.СтрШаблон_("%1.exe", СтрокаЗапуска1с); + КонецЕсли; + + Результат = КонтекстЯдра.СтрШаблон_( + """%1"" ENTERPRISE /IBConnectionString""%2""%3%4 /TestClient -TPort%5 /L%6 %7 /DisableStartupMessages /DisableStartupDialogs", + СтрокаЗапуска1с, + СтрЗаменить(СтрокаСоединенияИнформационнойБазы(), """", """"""), + ?(ПустаяСтрока(ИмяПользователя), "", " /N""" + ИмяПользователя + """"), + ?(ПустаяСтрока(Пароль), ""," /P""" + Пароль + """"), + XMLСтрока(Порт), + ТекущийЯзык(), + ДопПараметры); + + Возврат Результат; + +КонецФункции + +&НаСервереБезКонтекста +Функция ИмяТекущегоПользователя() + + ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь(); + + Если ТекущийПользователь.АутентификацияОС Тогда + Возврат ""; + Иначе + Возврат ТекущийПользователь.Имя; + КонецЕсли; + +КонецФункции + +&НаКлиенте +Функция ТаймаутВСекундах() + + Возврат 120; + +КонецФункции + +&НаКлиенте +Функция ТекстСкриптаЗавершитьТестКлиент(НомерПорта) + + Результат = СтрШаблон("%1 call terminate", ТекстСкриптаИнформацияОЗапущенныхКлиентах(НомерПорта)); + + Возврат Результат; +КонецФункции + +&НаКлиенте +Функция ТекстСкриптаИнформацияОЗапущенныхКлиентах(НомерПорта) + + Результат = + "wmic process where (CommandLine Like ""%/TESTCLIENT%"" And ExecutablePath Like ""%1cv8c%"") "; + + Если Не ЗначениеЗаполнено(НомерПорта) Тогда + Возврат Результат; + КонецЕсли; + + Возврат СтрЗаменить( + Результат, + "%/TESTCLIENT%", + "%/TESTCLIENT -TPort" + НомерПорта + "%"); + +КонецФункции + +&НаКлиенте +Функция ПолноеИмяИсполняемогоФайла() + + Возврат КонтекстЯдра.СтрШаблон_("%1%2%3", + КаталогПрограммы(), + "1cv8c", + РасширениеИсполняемогоФайла()); + +КонецФункции + +&НаКлиенте +Функция РасширениеИсполняемогоФайла() + + Если ЭтоLinux() Тогда + Возврат ""; + Иначе + Возврат ".exe"; + КонецЕсли; + +КонецФункции + +&НаКлиенте +Функция ЭтоLinux() + + СисИнфо = Новый СистемнаяИнформация; + ВерсияПриложения = СисИнфо.ВерсияПриложения; + + Возврат Найти(Строка(СисИнфо.ТипПлатформы), "Linux") > 0; + +КонецФункции + +// Записать примечание в журнал регистрации +// +// Параметры: +// ПостфиксСобытия - Строка - Может быть пустым +// Текст - - +// +&НаСервереБезКонтекста +Функция ЗаписатьОшибкуВЖурналеРегистрации(Знач ОписаниеОшибки, ПостфиксСобытия = "") + ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); // эта пляска для случаев когда ПостфиксСобытия будет пустой, что б в конце не осталась точка + ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки); + + Возврат ОписаниеОшибки; +КонецФункции + +// Записать примечание в журнал регистрации +// +// Параметры: +// ПостфиксСобытия - Строка - Может быть пустым +// Текст - - +// +&НаСервереБезКонтекста +Процедура ЗаписатьПредупреждениеВЖурналРегистрации(Знач ТекстОшибки, ПостфиксСобытия = "") + ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); + ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), + УровеньЖурналаРегистрации.Предупреждение, , , + ТекстОшибки); + +КонецПроцедуры + +&НаСервереБезКонтекста +Процедура ЗаписатьИнформациюВЖурналРегистрации(Знач Текст, ПостфиксСобытия = "") + ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); + ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), УровеньЖурналаРегистрации.Информация,,, Текст); +КонецПроцедуры + +// Записать примечание в журнал регистрации +// +// Параметры: +// ПостфиксСобытия - Строка - Может быть пустым +// Текст - - +// +&НаСервереБезКонтекста +Функция ЗаписатьПримечаниеВЖурналРегистрации(Знач Текст, ПостфиксСобытия = "") + ИмяСобытия = СтрРазделить(ИмяСобытияЖР()+"."+ПостфиксСобытия, ".", Ложь); // эта пляска для случаев когда ПостфиксСобытия будет пустой, что б в конце не осталась точка + ЗаписьЖурналаРегистрации(СтрСоединить(ИмяСобытия, "."), УровеньЖурналаРегистрации.Примечание,,, Текст); + + Возврат Текст; +КонецФункции + +&НаСервереБезКонтекста +Функция ИмяСобытияЖР() + + Возврат "VanessaADD.ТестКлиенты"; + +КонецФункции + +&НаКлиенте +Процедура ЗапомнитьДанныеТестКлиента(ТестКлиент, ИмяПользователя, Порт, ДопПараметры) + + ДанныеТестКлиента = Новый Структура; + ДанныеТестКлиента.Вставить("ТестКлиент", ТестКлиент); + ДанныеТестКлиента.Вставить("ИмяПользователя", ИмяПользователя); + ДанныеТестКлиента.Вставить("Порт", Порт); + ДанныеТестКлиента.Вставить("ДопПараметры", ДопПараметры); + + Если ЗапущенныеТестКлиенты = Неопределено Тогда + ЗапущенныеТестКлиенты = Новый Массив; + КонецЕсли; + + ЗапущенныеТестКлиенты.Добавить(ДанныеТестКлиента); + +КонецПроцедуры + +&НаКлиенте +Функция НайтиЗапущенныйКлиент(ИмяПользователя, Порт) + + Если Не ЗначениеЗаполнено(ЗапущенныеТестКлиенты) Тогда + Возврат Неопределено; + КонецЕсли; + + Для Каждого ТекЗапущенныйКлиент Из ЗапущенныеТестКлиенты Цикл + Если ТекЗапущенныйКлиент.ИмяПользователя = ИмяПользователя + И ТекЗапущенныйКлиент.Порт = Порт Тогда + Возврат ТекЗапущенныйКлиент.ТестКлиент; + КонецЕсли; + КонецЦикла; + +КонецФункции + +&НаКлиенте +Функция ПолучитьПорт(Знач Порт) + Если Не ЗначениеЗаполнено(Порт) Тогда + Порт = ПортПоУмолчанию(); + КонецЕсли; + + Если ТипЗнч(Порт) <> Тип("Число") Тогда + Порт = Число(Порт); + КонецЕсли; + + ЗаписатьИнформациюВЖурналРегистрации(СтрШаблон("Будет использован порт: ""%1""", Порт)); + Возврат Порт; +КонецФункции + +&НаКлиенте +Функция НажатьКнопкуМодальногоДиалога(Знач ОписаниеМодальногоОкна, Знач Кнопки) + Перем ИндексКнопки; + + Если Не ОписаниеМодальногоОкна.Свойство("Кнопка", ИндексКнопки) Тогда + Возврат Ложь; + КонецЕсли; + + Если ИндексКнопки = Неопределено ИЛИ ИндексКнопки < 0 Тогда + КонтекстЯдра.ВывестиСообщение("Индекс кнопки не должен быть 0 или меньше 0", СтатусСообщения.ОченьВажное); + Возврат Ложь; + КонецЕсли; + + Если ИндексКнопки >= Кнопки.Количество() Тогда + КонтекстЯдра.ВывестиСообщение("Индекс кнопки не должен быть больше количества кнопок в форме " + Кнопки.Количество(), + СтатусСообщения.ОченьВажное); + Возврат Ложь; + КонецЕсли; + + КонтекстЯдра.Отладка(" -->> НажатьКнопкуМодальногоДиалога - Индекс нажимаемой кнопки " + ИндексКнопки); + + Попытка + Кнопки[ИндексКнопки].Нажать(); + Возврат Истина; + Исключение + Инфо = ИнформацияОбОшибке(); + ОписаниеОшибки = "Ошибка нажатия на кнопку. + |" + ПодробноеПредставлениеОшибки(Инфо); + + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки, КлючНастройкиМодальныхОкон()); + + КонтекстЯдра.ВывестиСообщение("Не удалось нажать кнопку в форме", СтатусСообщения.ОченьВажное); + КонецПопытки; + + Возврат Ложь; +КонецФункции + +&НаКлиенте +Функция НажатьКнопкуМодальногоДиалогаЕслиНаФормеВсегоОднаКнопка(Знач Кнопки, Заголовок) + Если Кнопки.Количество() <> 1 Тогда + Возврат Ложь; + КонецЕсли; + + Попытка + Кнопки[0].Нажать(); + Возврат Истина + Исключение + ОписаниеОшибки = "Ошибка нажатия на кнопку. + |" + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()); + ЗаписатьПредупреждениеВЖурналРегистрации(ОписаниеОшибки, КлючНастройкиМодальныхОкон()); + + КонтекстЯдра.ВывестиСообщение("Не удалось нажать кнопку в форме " + Заголовок, + СтатусСообщения.ОченьВажное); + + Возврат Ложь; + КонецПопытки; +КонецФункции + +&НаКлиенте +Функция ДляСравнения(Знач Строка) + Возврат НРег(Строка); +КонецФункции + +&НаКлиенте +Функция НайтиПодходящееЗначениеПоКлючуВКоллекции(Знач Соответствие, Знач ПроверяемаяСтрока) + ПроверяемаяСтрока = ДляСравнения(ПроверяемаяСтрока); + Значение = Соответствие.Получить(ПроверяемаяСтрока); + Если Значение <> Неопределено Тогда + Возврат Значение; + КонецЕсли; + + Для каждого КлючЗначение Из Соответствие Цикл + СтрокаИлиШаблон = ДляСравнения(КлючЗначение.Ключ); + Если КонтекстЯдра.СтрокаСоответствуетШаблону(ПроверяемаяСтрока, СтрокаИлиШаблон) Тогда + Возврат КлючЗначение.Значение; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; +КонецФункции + +&НаКлиенте +Функция РазложитьСтрокуВМассивПодстрок(Знач Строка, Знач Разделитель = ",", + Знач ПропускатьПустыеСтроки = Неопределено) Экспорт + + Результат = Новый Массив; + + // для обеспечения обратной совместимости + Если ПропускатьПустыеСтроки = Неопределено Тогда + ПропускатьПустыеСтроки = ?(Разделитель = " ", Истина, Ложь); + Если ПустаяСтрока(Строка) Тогда + Если Разделитель = " " Тогда + Результат.Добавить(""); + КонецЕсли; + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Позиция = Найти(Строка, Разделитель); + Пока Позиция > 0 Цикл + Подстрока = Лев(Строка, Позиция - 1); + Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда + Результат.Добавить(Подстрока); + КонецЕсли; + Строка = Сред(Строка, Позиция + СтрДлина(Разделитель)); + Позиция = Найти(Строка, Разделитель); + КонецЦикла; + + Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Строка) Тогда + Результат.Добавить(Строка); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +&НаКлиенте +Функция СтрНачинаетсяС_(Строка, СтрокаПоиска) Экспорт + Возврат Найти(Строка, СтрокаПоиска) = 1; +КонецФункции + +/// Объединяет строки из массива в строку с разделителями. +// +// Параметры: +// Массив - Массив - массив строк которые необходимо объединить в одну строку; +// Разделитель - Строка - любой набор символов, который будет использован в качестве разделителя. +// +// Возвращаемое значение: +// Строка - строка с разделителями. +// +&НаКлиенте +Функция СтрСоединить_(Массив, Разделитель = ",") Экспорт + + Результат = ""; + + Для Индекс = 0 По Массив.ВГраница() Цикл + Подстрока = Массив[Индекс]; + + Если ТипЗнч(Подстрока) <> Тип("Строка") Тогда + Подстрока = Строка(Подстрока); + КонецЕсли; + + Если Индекс > 0 Тогда + Результат = Результат + Разделитель; + КонецЕсли; + + Результат = Результат + Подстрока; + КонецЦикла; + + Возврат Результат; +КонецФункции + +&НаКлиенте +Процедура УстановитьНастройкиМодальныхОконПоУмолчанию() + НастройкиМодальныхОкон = Новый Структура; + ЗаголовкиМодальныхОкон = Новый Соответствие; + ПоляМодальныхОкон = Новый Соответствие; + + ЗаголовкиСистемныхОкон = ЗаголовкиСистемныхОкон(); + + Описание = Новый Структура; + НастройкиМодальныхОкон.Вставить("Предприятие", Описание); + Описание.Вставить("Заголовки", ЗаголовкиСистемныхОкон); + Описание.Вставить("Кнопка", 0); + + Описание = Новый Структура; + НастройкиМодальныхОкон.Вставить("ПредупреждениеБезопасности", Описание); + Заголовки = Новый Массив; + Описание.Вставить("Заголовки", Заголовки); + Заголовки.Добавить("Предупреждение безопасности"); + Описание.Вставить("Кнопка", 0); + + Описание = Новый Структура; + НастройкиМодальныхОкон.Вставить("ИзменениеДанных", Описание); + Поля = Новый Массив; + Описание.Вставить("Поля", Поля); + Поля.Добавить("данные были изменены"); + Поля.Добавить("сохранить данные"); + Описание.Вставить("Кнопка", 1); + + Описание = Новый Структура; + НастройкиМодальныхОкон.Вставить("ДанныеБылиИзменены", Описание); + Заголовки = Новый Массив; + Описание.Вставить("Заголовки", Заголовки); + Заголовки.Добавить("Данные были изменены"); + Описание.Вставить("Кнопка", 1); + + Описание = Новый Структура; + НастройкиМодальныхОкон.Вставить("ВыборТипаДанных", Описание); + Заголовки = Новый Массив; + Описание.Вставить("Заголовки", Заголовки); + Заголовки.Добавить("Выбор типа данных"); + Описание.Вставить("Кнопка", 0); + + Описание = Новый Структура; + НастройкиМодальныхОкон.Вставить("СписокЗначений", Описание); + Заголовки = Новый Массив; + Описание.Вставить("Заголовки", Заголовки); + Заголовки.Добавить("Список значений"); + Описание.Вставить("Кнопка", 0); + + УстановитьНастройкиМодальныхОкон(НастройкиМодальныхОкон, ЗаголовкиСистемныхОкон); + +КонецПроцедуры + +&НаКлиенте +Функция ЗаголовкиСистемныхОкон() + + Результат = Новый Массив; + + Результат.Добавить("1С:Предприятие"); + Результат.Добавить("1C:Enterprise"); + + Возврат Результат; + +КонецФункции + +&НаКлиенте +Функция СведенияОЗанятыхПортах() + + Результат = Новый Структура; + Результат.Вставить("Порты", Новый Массив); + Результат.Вставить("Процессы", Новый Соответствие); + + // файл в методе не будет удаляться, т.к. в асинхронном режиме это довольно неудобно. сервер 1С удалит сам. + ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt"); // BSLLS:MissingTemporaryFileDeletion-off + + Если НЕ ЭтоLinux() Тогда + СтрокаЗапуска = "netstat -ano > """ + ИмяВременногоФайла + """ 2>&1"; + + //TODO проверить быстрое использование ВыполнитьКомандуОСБезПоказаЧерногоОкна(..., Истина, Ложь); + //ВыполнитьКомандуОСБезПоказаЧерногоОкна(ТекстКоманды, Истина, Истина); + УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); + КодОтвета = УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(СтрокаЗапуска); + + Текст = ОткрытьФайл(ИмяВременногоФайла); + Если Текст = Неопределено Тогда + Возврат Результат; + КонецЕсли; + Если КодОтвета <> 0 Тогда + Ошибка = Текст.Прочитать(); + Текст.Закрыть(); + + КонтекстЯдра.ВывестиСообщениеВЛогФайл(СтрШаблон("%1ОШИБКА: Не удалось выполнить команду ""%2"", код ответа = %3 + |Ошибка: ""%4""", Символы.ПС, СтрокаЗапуска, КодОтвета, Ошибка)); + + ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("Не удалось выполнить команду ""%1"", код ответа = %2", СтрокаЗапуска, КодОтвета)); + Возврат Результат; + КонецЕсли; + + Пока Истина Цикл + Стр = Текст.ПрочитатьСтроку(); + Если Стр = Неопределено Тогда + Прервать; + КонецЕсли; + + Если Стр = "" Тогда + Продолжить; + КонецЕсли; + + Разбивка = СтрРазделить(Стр, " ", Ложь); + Если Разбивка.Количество() <> 5 Тогда + Продолжить; + КонецЕсли; + Порт_ = Разбивка[1]; + PID = Разбивка[Разбивка.ВГраница()]; + + Порт = ""; + Для НомерСимвола = 0 По СтрДлина(Порт_) - 1 Цикл + СимволСтроки = Сред(Порт_, СтрДлина(Порт_) - НомерСимвола, 1); + Если СимволСтроки = ":" Тогда + Прервать; + КонецЕсли; + Если Найти("0123456789", СимволСтроки) > 0 Тогда + Порт = СимволСтроки + Порт; + КонецЕсли; + КонецЦикла; + + Попытка + Порт = Число(Порт); + Результат.Порты.Добавить(Порт); + Результат.Процессы.Вставить(Порт, PID); + Исключение + Продолжить; + КонецПопытки; + КонецЦикла; + + Текст.Закрыть(); + + Иначе + + СтрокаЗапуска = "ss -tuwan4p 2>/dev/null | awk '{print substr($5, index($5, "":"")+1) "" "" substr($7, index($7, ""pid="")+4)}' | grep ""[\d]+\s[\d]*"" -Po | sort | uniq > """ + ИмяВременногоФайла + """"; + УправлениеПриложениями = КонтекстЯдра.Плагин("УправлениеПриложениями"); + УправлениеПриложениями.ВыполнитьКомандуОСБезПоказаЧерногоОкна(СтрокаЗапуска); + + Текст = ОткрытьФайл(ИмяВременногоФайла); + Если Текст = Неопределено Тогда + Возврат Результат; + КонецЕсли; + + Пока Истина Цикл + Стр = Текст.ПрочитатьСтроку(); + Если Не ЗначениеЗаполнено(Стр) Тогда + Прервать; + КонецЕсли; + + Разбивка = СтрРазделить(Стр, " ", Ложь); + Если Разбивка.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + + Порт = СокрЛП(Разбивка[0]); + Попытка + Порт = Число(Порт); + Результат.Порты.Добавить(Порт); + + Если Разбивка.Количество() = 2 Тогда + Результат.Процессы.Вставить(Порт, СокрЛП(Разбивка[1])); + КонецЕсли; + Исключение + Продолжить; + КонецПопытки; + КонецЦикла; + + Текст.Закрыть(); + КонецЕсли; + + //Для каждого СтрокаДанныеКлиентовТестирования Из ДанныеКлиентовТестирования Цикл // TODO + // Результат.Добавить(СтрокаДанныеКлиентовТестирования.ПортЗапускаТестКлиента); + //КонецЦикла; + + Возврат Результат; + +КонецФункции + +&НаКлиенте +Функция ОткрытьФайл(Знач ПутьФайла) + + Текст = Новый ЧтениеТекста; + Попытка + + Текст.Открыть(ПутьФайла, "UTF-8"); + + Исключение + + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ПолныйТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + + ПолныйТекстОшибки = СтрШаблон("Не удалось прочитать файл-результат команды получения занятых портов + |%1", ПолныйТекстОшибки); + + ЗаписатьОшибкуВЖурналеРегистрации(ПолныйТекстОшибки); + + Возврат Неопределено; + + КонецПопытки; + + Возврат Текст; + +КонецФункции + +&НаКлиенте +Функция НовоеОписаниеТестКлиента() + + Результат = Новый Структура; + Результат.Вставить("Клиент", Неопределено); + Результат.Вставить("Порт", 0); + + Возврат Результат; + +КонецФункции + +// Дополняет массив (взята типовая процедура) +// +// Параметры: +// МассивПриемник - Массив - массив, в который необходимо добавить значения. +// МассивИсточник - Массив - массив значений для заполнения. +// ТолькоУникальныеЗначения - Булево - если истина, то в массив будут включены только уникальные значения. +// +&НаКлиенте +Процедура ДополнитьМассив(МассивПриемник, Знач МассивИсточник, ТолькоУникальныеЗначения = Ложь) Экспорт + + Если ТолькоУникальныеЗначения Тогда + + УникальныеЗначения = Новый Соответствие; + + Для Каждого Значение Из МассивПриемник Цикл + УникальныеЗначения.Вставить(Значение, Истина); + КонецЦикла; + + Для Каждого Значение Из МассивИсточник Цикл + Если УникальныеЗначения[Значение] = Неопределено Тогда + МассивПриемник.Добавить(Значение); + УникальныеЗначения.Вставить(Значение, Истина); + КонецЕсли; + КонецЦикла; + + Иначе + + Для Каждого Значение Из МассивИсточник Цикл + МассивПриемник.Добавить(Значение); + КонецЦикла; + + КонецЕсли; + +КонецПроцедуры + +&НаКлиентеНаСервереБезКонтекста +Функция ЗначениеВМассиве(Значение) + Массив = Новый Массив; + Массив.Добавить(Значение); + + Возврат Массив; +КонецФункции + +&НаКлиенте +Функция ДанныеКешаПроверкиОкон(Знач ОкноПриложения) + Результат = КешПроверкиОкон.Получить(НормализоватьЗаголовокОкна(ОкноПриложения)); + Если ЗначениеЗаполнено(Результат) Тогда + Возврат Результат; + КонецЕсли; + + Возврат Новый Структура; +КонецФункции + +&НаКлиенте +Процедура ДобавитьВКешПроверкиОкон(Знач ОкноПриложения, Знач Успешно, Знач Описание) + Структура = НовыйРезультатКешаПроверкиОкон(); + Структура.Успешно = Успешно; + Структура.Описание = Описание; + КешПроверкиОкон.Вставить(НормализоватьЗаголовокОкна(ОкноПриложения), Структура); +КонецПроцедуры + +&НаКлиенте +Функция УдалитьИзКешаПроверкиОкон(Знач ОкноПриложения) + КешПроверкиОкон.Удалить(НормализоватьЗаголовокОкна(ОкноПриложения)); +КонецФункции + +&НаКлиенте +Функция НовыйРезультатКешаПроверкиОкон() + Возврат Новый Структура("Успешно, Описание", Ложь, ""); +КонецФункции + +// обертка над ПолучитьПодчиненныеОбъекты. Попытка обойти ошибку "Ошибка сетевого взаимодействия при вызове" +// +// Параметры: +// ТестКлиент - ТестируемоеПриложение, ТестируемоеОкноКлиентскогоПриложения +// +// Возвращаемое значение: +// ФиксированныйМассив - Получает коллекцию объектов, подчиненных текущему. +// +&НаКлиенте +Функция ПодчиненныеОбъекты(ТестКлиент) + Результат = Новый Массив; + Если ТестКлиент = Неопределено Тогда + Возврат Результат; + КонецЕсли; + + Попытка + Результат = ТестКлиент.ПолучитьПодчиненныеОбъекты(); + Если Результат <> Неопределено Тогда + Возврат Результат; + КонецЕсли; + Исключение + Инфо = ИнформацияОбОшибке(); + ПОшибка = ПодробноеПредставлениеОшибки(Инфо); + + СведенияОЗанятыхПортах = СведенияОЗанятыхПортах(); + ДопСведения = Новый Массив(); + Для Каждого ТК Из ЗапущенныеТестКлиенты Цикл + ДопСведения.Добавить(СтрШаблон("Данные тест-клиента. Порт ""%1"", PID клиента ""%2""", ТК.Порт, СведенияОЗанятыхПортах.Процессы[ТК.Порт])); + КонецЦикла; + + КонтекстЯдра.ВызватьОшибкуПроверки(ЗаписатьОшибкуВЖурналеРегистрации(СтрШаблон("Не удалось получить подчиненные объекты + |Количество запущенных клиентов: %1 + |СведенияОЗанятыхПортах: + | %2 + | + |Ошибка: + | %3", ЗапущенныеТестКлиенты.Количество(), СтрСоединить(ДопСведения, Символы.ПС), ПОшибка))); + + КонецПопытки; + + Возврат Результат; +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Функция МассивСодержит(Массив, Элемент) + + Если ТипЗнч(Массив) <> Тип("Массив") Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого М Из Массив Цикл + Если СтрНайти(Элемент, М) > 0 ИЛИ СтрНайти(М, Элемент) > 0 Тогда // где-то может стоять точка в конце, где-то нет. + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; +КонецФункции + +// } Helpers