- 크롬 시크릿 모드로 할 때는 확장프로그램의 세부정보로 들어가서 '시크릿 모드에서도 허용'을 True로 바꿔줘야 함
- 탭을 꺼야 하는 경우, 브라우저의 타이틀을 유니크하게 잡을 수 있다면 Attach Browser - Close tab이 가장 안정적. 다만 그럴 수 없다면 close할 탭의 Element(그 창에만 있는 Element)에 Send hotkey로 ctrl+w를 써야 함. (이 경우 Retry scope으로 not exist 체크를 해줘야 함)
- Website를 다른 방식으로 켜야 하는 케이스가 있다면 "chrome.exe까지의 경로" "웹사이트주소" 형태로 CMD에서 실행하면 된다. 사이트주소 파라미터는 그냥 띄어쓰기로 받아짐. (Uipath 기준으로 Start Process)
- open browser는 cmd에서 웹사이트 주소를 ""로 감싸지 않고 전달하기 때문에 Chrome에서 띄어쓰기가 포함된 URL의 경우 의도와는 달라진 결과를 얻을 수도 있다. 따라서 Uri.EscapeUriString(vURL) 형태로 URL을 인코딩하거나 빈 칸을 "+" 혹은 "%20"으로 Replace하여 진행하는 것을 추천.
값을 바꿀 때 "exit_type": "none" 으로 해야 함. 따옴표 빼먹으면 인식 X. (preference.bad 파일이 새로 생김)
* 경로중 Default는 기본으로 켰을 때 profile 유저를 말하며, 다른 유저를 생성하면 그 이름으로 폴더가 생기고 preference를 따로 가져간다는 의미. 이를 이용해 멀티세션 작업 등을 생각할 수도 있음. 다만 봇이 많아질수록 관리포인트가 그만큼 늘어난다는 것에 유의.[단, 환경세팅을 할 때 OS 템플릿을 써서 이미지로 import한다면 문제 없음]
- 크롬에서 다른 프로필을 만들고 켜려면 크롬뒤에 --profile-directory="프로필명" 을 파라미터로 넣어야 함. [start process 이용]
혹은 "EXEC P_CRM_CUSTOMER_S @DC, @CUST_NM"으로 주고 파라미터를 in방향으로 @DC, @CUST_NM으로 주면 됨
** 최근에는 프로시져를 거의 안 쓰는 추세. 이 방법밖에 없다면 이걸 쓰고 아니면 최대한 api로 insert나 get을 구현하는 것이 더 안정적이고 대세. 개인적으로는 RPA에서 프로시져를 써야 한다면 거의 대부분 잘못된 PI가 되었다고 판단함. RPA가 할 일이 아님. 굳이 role을 보자면 RPA는 그냥 테이블에 넣기만 하고 db내 function만 call해서 처리하는 게 효율적임
DataTable
- datatable.clone => 데이터 테이블의 헤더만 가져옴[copy하고 clear 안 해도 됨]
- sort datatable로 order by가 제대로 안 되는 경우[보통 인식 type의 문제]
dtContainer.AsEnumerable().OrderByDescending(Function (row) row(“기준컬럼”)).Select(Function (row) row).ToArray.CopyToDatatable() [C#에서는 Function(row) 대신 row=> 이런 형태로 쓴다]
- DT에서 ColumnName 변경 : dtData.Columns(index).ColumnName = "바꾸고자 하는 이름" (index 대신에 old name도 가능)
- datatable.rows.indexof(datarow)를 쓰면 필터가 됐더라도 해당 datarow의 index 번호를 알 수 있다. 다만 다른 table에 copy되기 전이어야 함.
- datatable에서 떨군 datarow도 기본 복사가 참조 복사임. 따라서 dtData에서 drDataRow를 꺼내 drDataRow 내의 정보를 바꾸면 dtData에서 해당 row의 정보도 바뀌게 됨. 이게 싫다면 역시 dt를 .copy로 하거나 해당 row의 rowstate를 땔 수 있게 다른 ArrayRow로 convert 해야 함
- Filter DataTable의 비교는 Equals가 아니라 = 이기 때문에 엑셀의 서식에 따라 틀어질 수 있음. 가령 Object 형태나 int 형태로 인식되어서 toString하여 비교하면 의도한 필터링이 안 되는 경우 존재. 따라서 엑셀의 형태를 통제할 수 있다면 Filter DataTable을 쓰고, 아니면 Select문을 구성하는 게 좋음
- Filter Table이 제대로 먹지 않을 때[역시 대부분 Type 인식의 문제]
=> dtOutput =(FrompIndtInput.SelectWherep(Column_Index).ToString.Equals("StringValue")Selectp).ToArray.CopyToDataTable <==== 둘 다 타입을 String으로 맞춰버리기 때문에 엑셀 서식으로 인한 타입 차이 제거
- Select문 구성보다는 가독성 좋은 소스가 좋아서 Filter Table을 꼭 쓰고 싶다면 다음과 같은 방법이 있음
[보통 거의 2단계에서 해결]
i) 비교되는 대상에 Tostring.Trim을 적용하고 되는지 체크
ii) i의 방법으로 안 되면 Filter Table 앞에서 input Table 루프를 만들어 row("비교하려는 컬럼명")=row("비교하려는 컬럼명").Tosring 으로 Assign하고 되는지 체크
iii) i,ii 둘 다 안 되는 경우 해당 DT의 원데이터가 Excel이라면 Excel을 읽는 방식을 변경(Excel Scope <> File Excel)
- 엑셀에서 Null값을 읽었을 때, Excel Application Scope을 써서 Read Range하면 []로 들어오지만, File 패키지에 있는 Activity로 Read Range를 하면 ""로 들어옴. (DataTable에서는 둘 다 그냥 ,, 형태로 들어가 있지만 DataRow로 떼어보면 [], ""로 달라짐.) 이게 간혹 FilterTable에서 값이 어긋나는 상태를 유발하는 것일 수 있음.
- DT가 Null이면 Merge가 되지 않음. DT에 Header가 없어도 Merge는 되나 MissingSchemaAction 옵션에 따라 컬럼이 옆으로 추가됨. 따라서 정합성을 맞춰 Merge를 쓰기 위해서는 둘 다 컬럼을 없애든가 둘 다 컬럼을 맞춰줘야 함. [둘 다 컬럼을 없애면 자동생성 이름으로 맞춰짐]
- 컬럼의 순서를 바꾸고 싶다면 Method를 쓰거나 Filter Table을 써야 하는데 후자가 더 쉽고 간편함
[단, Filter Table에서 컬럼 순서를 바꿀 때 컬럼명이 틀려도 에러가 나지 않으므로 체크 필요]
- DT1의 row를 다른 DT로 할당하고 싶다면 Assign할 때 row가 아닌 row.ItemArray로 할당해야 함[일반적으로 row는 추출된 dt에 종속되기 때문. 또 이렇게 더하는 경우 넣고자 하는 컬럼의 순서가 같아야 정합성이 보장됨.]
- row는 추출된 DT에 종속되기 때문에 row를 가져가서 다른 값으로 변경하면 DT내부 값도 변경됨. Argument로 이을 때도 마찬가지므로 주의. [일반적으로 간과하기 쉬운 게 Activity들에서 output으로 DT를 받을 때는 무조건 init을 하고 받아서 이런 특성을 인지하기 어려움]
- 따라서 참조 복사를 막기 위해선 DT.copy로 다른 DT에 Assign하여 진행해야 함
- Delete Row는 하면서 index가 바뀌기 때문에 마지막 인덱스부터 삭제해야 함
- DataTable의 Count가 0인 것과 DataTable이 Nothing인 것은 다름. 둘중 어느쪽인지 특정하기 어려운 경우 Build DataTable을 통해 일단 할당을 해놓고 Count를 세는 방법을 추천. 혹은 Nothing 체크를 먼저하고 그걸 통과한다면 Count를 세는 형태로 가야 함.
- DataTable의 Count가 0인 것과 DataTable이 nothing인 것은 다름. 특정하기 어렵다면 dtData isnot nothing AndAlso dtData.rows.count > 0 형태로 써주면 됨. 그럼 Nothing이 아닐 때만 AndAlso 구문을 검사하기 때문에 에러가 안 남.
- Filter Table에서 해당 컬럼을 Int로 인식하지 못 하는 경우 대소비교는 Start with를 이용.(가령 자연수를 남기고 싶다면 Start with "-", Start with "0" 으로 필터링) 혹은 Select문을 쓰거나 해당 DT를 루프돌려서 그 컬럼값을 Cint 해주고 진행.
- DataTable에서 별도의 index까지만 추출하기 위해선 dtvar.ASEnumerable.Take(2000).CopyToDataTable식으로 씀. 반대로 특정 index까지 제외하고 가려면 Take 대신 skip을 씀.
- String으로 쌓아놓고 나중에 Generate로 DataTable을 만드는 설계는 오류 가능성이 큼. 특별한 이유가 없다면 바로 DT에 Insert. (Gernerate DataTable은 어디까지나 String으로 가져올 수밖에 없는 OCR 같은 기능을 위한 것임)
- DataTable의 컬럼 구조를 동일하게 가져가고 싶다면 한번 해당 Data를 담은 다음에 Clear DataTable해서 씀. 일반적으론 해당 DT를 유지하고 다른 DT를 만들어 내용을 담기 때문에 Assign으로 Copy한 후 Clear. [이러면 Merge를 쓸 때 내용이 없더라도 NullPointException이 안 걸림]
1. 비교하는 DT가 같은 구조가 아닌 경우(가령 한쪽에는 Result 컬럼을 추가했다든가)
2. 같은 구조지만 중간에 다른 값을 할당하는 구조를 놓친 경우[한 마디로 단순비교 불가한 경우]
- DT의 컬럼순서를 특정 리스트에 있는 순서대로 바꿔야 하는 경우 :
0. 배열하고자 하는 이름 순으로 컬럼명이 들어가 있는 List를 생성
1. List에 대한 For each 생성
2. Loop안에invoke public method => SetOrdinal[param으로 loop의 index 지정]
=> List에 적힌 순서대로 컬럼 정렬됨
- 엑셀 내부에 '='이 포함돼 있는 경우 Write하게 되면 에러가 발생하거나 일부가 잘려서 쓰여짐. equal로 시작할 개연성이 있는 경우 체크 필수(가령 사용자 comment 등)
- 서브쿼리 : SELECT * FROM dt1 WHERE column IN (SELECT manyVar FROM dt2)
- Excel에서 Header없이 읽으면 Column0부터 순서대로 잡힘. Build DataTable는 Column1부터 잡혀있음. (엑셀에서 얻은 데이터를 Container하게 만들 테이블이 필요할 때 init 주의)
- #N/A 같은 오류들은 읽었을 때 다음과 같은 값으로 변형되기 때문에 이걸로 필터링해야 함
-2146826281 = #DIV/0!
-2146826246 = #N/A
-2146826245 = #GETTING_DATA
-2146826259 = #NAME?
-2146826288 = #NULL!
-2146826252 = #NUM!
-2146826265 = #REF!
-2146826273 = #VALUE!
전체적으로 그냥 다 막고 싶으면 -2146으로 StartWith 필터를 걸면 됨.(데이터 자체에 이런 값이 있지 않다면)
- Linq로 Groupby해서 동일한 항목은 더해야 하는 경우
(From row In dtContainer.AsEnumerable() Group row By gList = New With {Key .Name = row("키컬럼"), .이름= row("출력하려는 추가 컬럼")} Into gListGroup = Group Select dtContainer.Rows.Add({gList.Name.ToString, gList.이름.ToString, gListGroup.Sum(Function(x) CInt(x("더해지는컬럼").ToString))})).CopyToDataTable
- 특정 컬럼에 assign 할 때 invoke 에러가 나는 경우는 보통 max length를 넘는 데이터를 assign하려고 해서 그럼. max length는 -1로 하면 제일 편하고 아니면 적절히 크게 해주자.
Data Scraping
- Data scraping은 페이지가 뜨자마자 데이터가 로딩되기 전에 값을 추출해 빈 값을 가져오는 경우가 많음. 따라서 Retry Scope에서 output DT의 Rows가 0인지 체크하는 게 좋음.
- [주의] datascraping시에는 title이 같은 창들이 있으면, 에러나는 게 아니라 가장 처음 거를 가져옴 => 겹치지 않도록 Retry 시 Taskkill 이나 close tab 등 필수
- Data Scrapping의 Meta Data에 변수를 쓰려면 통으로 다른 데서 String을 할당하고 그 변수를 넣는 게 편함[20.10.6 버전에서도 확장된 창에서 변수를 넣을 수 없음]
- Data Scrapping을 반복적으로 사용하는 경우 DT가 Init되지 않는 현상이 있음. 같은 Data Table로 데이터를 가져오는 경우 앞에 DataTable Init을 추가하는 게 좋음.
- 기본적으로 String Format을 날짜로 인식시키기 위해서는 CDate를 사용. (yyyy, MM, dd간 구분자 없으면 강제 인식 필요)
- 말일 계산법 : (날짜).adddays(1-날짜.day).addmonth(1) 혹은 date.daysinmonth(날짜.year,날짜.Month)
- String 변수가 Date변수로 인지되지 않는 경우, 포맷을 정해서 강제 인식. Date.ParseExact(Str,"인식형식",System.Globalization.CultureInfo.CurrentCulture).ToString("원하는형식")
- Date값에서 분을 늘리고 싶다면 date1.AddMinutes(Value) 형식으로 쓸 수 있음. 혹은 DateAdd("n",Value,date1) 식으로도 가능. (기능은 같은데 DateAdd는 조정하는 값에 대한 포맷 문자열을 알아야 된다는 것때문에 조금 귀찮음.)
- OADate(OLE Automation Date)는 숫자형태로 표현됨. 43210 같이 Double 형태로 표현되며 System.DateTime.FromOADate(43210).ToString("yyyy-MM-dd") 를 써서 DateType인 String으로 변형할 수 있음.
- OADate는 1이하로 쓰면 시간만 나옴. (1일중 몇 %인지 보면 됨)
- 날짜 계산은 연산으로 가능함. 뒤에 차이를 무엇으로 뽑고 싶은지 메서드를 붙이면 됨. (CDate("날짜str")-Today).TotalDays => 이런 경우 Double로 받아야 되지만 귀찮다면 Cint를 붙임.
- String변수가 어떤 형식이 아닐 수도 있는 경우에 Parsing하려면 "형식.TryParse"라는 함수가 있음. Date.TryParse(sTargetStr, 비어있는 Date변수)를 하면 True, False로 Return해줌.
Download & Upload
- 다른 이름으로 저장할 때 path를 type into로 잡으려면 send window message로 하는 게 가장 안정적인 듯[다른 거는 Device에 따라 종종 path를 바꾸지 못하고 저장됨]
- 파일을 업로드할 때 경로를 ""로 묶고 띄어쓰기를 구분자로 넣으면 한번에 업로드 됨. 다만 전체 길이제한이 있음 주의.(한영 무관하게 260자만 들어감). 이런 이슈를 피할 수 있다면 한번에 업로드하여 퍼포먼스 향상 가능.
- Wait for Download라는 Activity가 있음. 경로 입력 시 다운로드를 기다려 파일이름을 갖다 줌. 또는 alphabet 패키지의 get newest file을 통해 받으려는 파일이 제대로 다운로드 됐는지 체크 가능. 크롬의 경우 crdownload 어쩌고 하는 임시파일로 받아짐.
- 웹에서 다른 이름으로 저장 관련 Selector는 App특성에 *를 넣거나 빼면 브라우저 상관없이 윈도우식 다운로드 창이 뜨는 곳에서는 다 동작함[다운로드 체크 관련해서 브라우저 상관없이 모듈화 가능]
=> 기본 방식은 하드 클릭, Simulate는 타겟 앱의 기능을 invoke, SendwindowMessages는 타겟 앱에 직접 구체적인 명령을 보내는 방식이라는 듯. Type into의 경우 기본 방식을 피해야 한/영 변환 등의 입력기 오류를 피해갈 수 있음.
- Type into에서 Simulate Type을 선택하는 경우 "["가 키입력 구문으로 해석되지 않음. 기본키나 SendwindowMessages에서 대괄호를 사용하고 싶은 경우 "["를 "[["으로 Escape가 가능하다. ("]]"는 Replace하지 않아도 됨) + (Selector가 없는 경우 simulate type은 자동으로 default로 정의되어 키 구문오류 발생할 수 있음)
- element를 잡았는데 관리자 권한 확인하라고 하는 경우 해당 Target 프로그램을 관리자 권한을 빼고 수행해보면 됨.
Start 프로세스로 cmd.exe까지는 프로그램 경로, 그 뒤는 Parameter로 주면 됨.
[다만 이 방법을 썼을 때 필요한 곳까지 접근하지 못 하는 경우 해당 시스템 관리자에게 문의해야 함]
- Selector에 변수를 넣고자 할 때는 {{변수명}}으로 쓸 수 있다. 혹은 Ctrl+Space을 누르면 선택창이 뜬다. [단, Arguments는 선택되지 않음]
- Selector내에서 계산이 필요한 경우 바로 계산하면 먹힘. 가령 idx = '3+{{iCnt}}*5' 식으로 쓸 수 있음. 다만 전체를 괄호로 감싼다든가 해서 계산의 Result가 int가 아닌 '(15)' 같은 형태면 안 먹힘. => 소스 가독성이 떨어지기 때문에 추천하지는 않음. 그냥 변수에 웬만하면 담아서 쓰도록 하자.
- Select Item으로 잡히지 않고 Span이나 DIV로 쌓여있는 선택 폼은 클릭-클릭 하지 않고 simulate click하면 보통 잡힘. 안 된다면 앞에 클릭을 하나 추가하면 거의 됨. (그냥 안쪽에 있으면서 클릭 트리거에 반응하기 때문에 Back단으로 클릭하면 선택됨.)
- Layer가 겹쳐진 형태(예를 들어 팝업의 팝업의 팝업의 팝업)인 경우 최상단에 있는 것을 제대로 못 잡아 올 때가 있다.(특히 모달식) 그 경우 일반적으로 Type into가 제대로 안 먹힐 수 있음(뒤쪽 레이어에 input을 때리기 때문) => image click이 필요할 수 있음
- 보통 ListItem 형태인데 DIV로 잡혀있거나, Calendar Input인데 값이 입력되지 않는 경우 Type into에서 AlterIfDisable과 Simulate Type을 설정하고 시도하면 대개 값이 변경됨. Element에 값 자체를 때려넣는 방식이라 되는 듯함. [개발자 도구에서 넣듯이]
- Object의 ID값이 자주 변하는데 위치는 상대적으로 고정된 경우 Anchor Base를 쓰면 됨. 주의할 점은 Anchor가 되는 것이든 Action이 되는 것이든 대상을 지정할 때 Anchor Base 영역 안에서 할 것. [find element + anchor base]
- Type into로 키입력 하는 방법(단, simulate type으로 하면 문자 그대로 입력됨) : key down => [d(ctrl)] /// key up => [u(ctrl)] /// key down and up [k(ctrl)]
- 역으로 simulate type이 아닌 키입력을 하는 값이 "["가 들어올 수 있다면 체크해야 함. 그렇지 않으면 에러가 발생.
- Type into의 방식에는 default, simulateType, sendWindowMessage가 있다. default는 입력기를 타고 그대로 입력하는 방식이며 simulateType은 해당 어플리케이션과 직접 통신하고 sendWindowMessage는 dll로 통신한다. => 다른 UI 방식중에도 비슷하게 방식을 고를 수 있는 Activity들이 있음.
- Column Name으로 index 얻는 방법. DT.Columns("ColumnName").Ordinal
- Generate Data Table을 하면 구분자를 설정해 테이블을 만들 수 있음[OCR이나 PDF 등을 통해 가져온 텍스트를 구조화] => 특정한 컬럼 형식이 없다면 CSV Parse를 하는 게 가장 베스트
- AlterDisable을 체크하면 값 할당이 되지 않는 날짜 Input에도 값을 넣을 수 있음
- MES 시스템에서 그리드가 전혀 안 잡히는 경우 index를 잡기 위해서 offset을 수열로 구성할 수 있다. 가령 index 1번째 클릭이 X:30 / Y:30 이고 2번째 클릭이 X:30 / Y:40 이라면 Y:30+10n 형태로 구성할 수 있다. 다만 페이징은 상황에 따라 고민해볼 부분. [보통 page down으로 처리]
- Spotfire 같은 시스템은 특정 object를 선택하고 ctrl+c하면 해당 값이 가지는 텍스트를 가져옴. 따라서 Ctrl+a로 선택해 가져오면 데이터를 분석해 특정 처리를 하는 것도 가능하다. 다만 이슈는 파이차트 등을 클릭해야 되는 경우임
- 로딩 시에 뜨는 object는 로딩이 끝나면 없어지는 게 아니라 크기를 0으로 줄이는 경우가 많다. 이럴 때는 position이라는 속성을 통해 Uipath.core.region 타입의 변수로 담기는 정보를 받아와 구별할 수 있다. 이를 이용해 분기하는 것도 가능하지만, 굳이 그러기 보다는 로딩 중에는 클릭해도 반응이 없는 버튼을 클릭하고 클릭에 반응이 오면 로딩이 종료된 것으로 체크하는 게 더 쉽다.
- 그럼에도 Loading Region을 읽어오려면 Uipath.Core.Region 타입의 변수를 만들어 position 속성을 받고, rRegion.Rectangle.Value.Width > 0 같은 옵션을 통해 로딩이 끝났음을 알 수 있음. #Region #Rectangle
- Region을 초기화할 필요가 있다면 New Uipath.Core.Region(New Rectangle(100, 100, 100, 100)) 이런 형태로 할 수 있음 #Region 초기화
- Web에서 text를 가져오는 경우 text-overflow가 적용되어 가져올 수 있음. 보통 title 같은 것으로 보완해놓기 때문에 그걸 가져오든, 어떤 depth를 들어가서 따로 가져오든 해야 함
- Web에서 &라는 문자가 있는 경우 가져오면 & 형태가 될 수 있음. 거꾸로 &라는 문자가 있을 수 있는데 해당 위치에 변수를 넣은 경우 &로 Replace 해주어야 함. 이렇게 다른 형태로 변경되어 출력되는 html 버전의 특수문자들이 있음.
- UIElement가 초기화 되지 않았다라는 메세지가 뜨면 거의 Attach window나 Attach Browser가 잡혀있음. 메인 프로그램에 대한 정보가 거기 담겨있어 Element에는 생략되었기 때문에 나오는 현상. Element 자체에 Attach에 있는 정보를 추가하든 해야 진행 가능.
- 환경에 따라 Set to Clipboard 에러가 나는 경우가 있음. 이땐 Uiautomation.Activities를 업데이트 하니 해결되었음. [이외의 Set to Clipboard 에러는 빈 문자열이 아닌 null을 할당한 경우임]
Excel
- Excel Application Scope에서 Create if not exist 옵션을 쓰는 경우 파일명에 대괄호가 들어가면 안 됨(읽을 때는 상관없으나 생성 로직 중 문법으로 인식되어 오류나는 것으로 보임. file is corrupt 메세지로 출력)
- Excel application Scope은 엑셀 설치없이 사용 불가능(엑셀 설치가 안 된 경우 system-file-workbook에서 사용)
- 행의 Header를 특정해야 되는 경우 범위를 잘 지정해야 함. [전체를 읽으면 무조건 첫 행이 헤더로 인식됨]
- 엑셀에서 Null값을 읽었을 때, Excel Application Scope을 써서 Read Range하면 []로 들어오지만, File 패키지에 있는 Activity로 Read Range를 하면 ""로 들어옴. (DataTable에서는 둘 다 그냥 ,, 형태로 들어가 있지만 DataRow로 떼어보면 [], ""로 달라짐.) 이게 간혹 FilterTable에서 값이 어긋나는 상태를 유발하는 것일 수 있음.
- Excel Application Scope의 Save Changes 옵션은 값이 하나 바뀔 때마다 세이브함. 따라서 파일이 무거운 경우 옵션을 제거하고 단계별로 save workbook을 쓰는 게 좋음. [이래야 디버깅용 자료 떨구기도 좋을 듯]
- 엑셀에서 Column Name을 가져올 때 EasyExcel의 get Column Name을 쓰면 됨. [int값만 입력하면 알파벳 리턴해줌]
- (주의) 엑셀에서 뜨는 Prompt창 일부에서 Type Into를 쓸 때 Empty Field를 선택하면 Excel Range String이 들어가는 경우가 있었음. ($A$14:$C$99 선택했던 범위 뒤로 Text가 Append됨)
- UP에서 Join은 출력열을 조정하지 못 해서 무조건 각각 컬럼이 다 나옴. 가령 Key, Value / Key, Value 인 DT 2개를 Join했을 때 Key, Value, Key_1, Value_1 형태로 결과가 나옴. 이런 경우 그냥 Filter Table로 한쪽을 잘라서 쓰는 것도 방법
- 엑셀을 읽을 때 시트에서 한 DT만 읽어올 거라면 시작셀만 써도 알아서 읽어옴. 다만 DT를 2개 이상 가져와야 된다면 더 큰 범위에 있는 DT의 범위를 구체화 해야 함. (ex. Sheet1 // A1 || Sheet1 A15:E30) => 범위 자동인식에 대해 파일마다 이슈가 있을 수 있으므로 동적으로 가야되는 경우가 아니면 입력.
- VLOOKUP이나 INDEX 등 참조함수를 걸어주는 경우, 해당 엑셀 파일이 아닌 다른 엑셀 파일에서 걸어주는 경우 Target 엑셀을 연 상태에서 작업해 주어야 함. [Target Excel을 바깥쪽 Scope으로 감싸 진행]
- VLOOKUP이나 INDEX 등 참조함수를 쓴 경우, 일반적으로쓰고나서 값복사를 통해 덮어쓰기 해주는 것이 좋음[현업이 받았을 때는 Target 엑셀이 없을 가능성이 크므로]
- 엑셀의 경우 Scope로 Open한 다음 Attach - Maximize할 때 Title을 그냥 '*' 형태로 할당하면 에러가 남. 원인은 모르겠으나 '*Excel*' 형태로 고치면 해결됨. [아마도 Excel.exe 관련 다른 프로그램이 켜지면서 창을 혼동하는 Exception이 뜨는 게 아닌가 하는 추정만 하고 있음]
- Excel Scope에서 꺼질 때 저장하는 기능은 필터링이나 영역선택을 저장하지는 않음. 그것까지 저장하고 싶다면 따로 Save Workbook 기능 사용해야 함.
- Excel Autofill을 하는 경우 한 줄이 아닌 여러 줄의 범위 Autofill을 하면 수식이 아닌 값일 때(가령 =VLOOKUP~~ 가 아닌 20210510일 때) 각각 다르게 동작함. 한 줄인 경우 복사가 되지만 여러 줄 범위가 되면 ROW에 따라 값이 변화함. [Autofill할 때 Ctrl을 누른 효과 / 아닌 효과가 각각 적용됨]
- xls파일을 xlsx로 Convert해야 하는 경우 “C:\Program Files\Microsoft Office\Office16\excelcnv.exe(해당 경로가 없다면 32비트 프로그램 폴더 또는 다른 버전에서 찾아보자) "-oice “"{input 파일 경로}”" ""{output 파일 경로}”"" 형태로 Command를 입력하는 게 가장 안정적. [Start Process를 이용해 앞단은 프로그램 경로에 -oice부터는 파라미터에 입력] (enc 같은 파일에서 변환하는 것도 가능해 보임)
- 특정 엑셀 파일에 대해 수기로 열면 문제가 없으나 UP로 열면 HRESULT가 뜨는 경우, NPOI(Author : NPOI Contributors)를 설치하면 보통 해결됨. 이는 NPOI가 엑셀을 Parsing 하는 데 다양한 예외까지 잡고 있기 때문으로 보임. (이 라이브러리는 엑셀이 없든 있든 동작해야 되므로)
- 특히 System-File에서 Workbook을 활용하는 경우 파일 문제는 거의 NPOI로 해결이 가능. (POI는 아파치에서 만든 엑셀 라이브러리이고 NPOI는 그것의 .Net 버전임)
- 엑셀에서 포맷을 안 바꾸고 싶으면 Excel scope에서 preserve format 체크 => 다만 row를 99999 이런 형식으로 쓰는 경우 매우 느려짐.[그 라인까지 포맷체크를 다 하기 때문] Read Column을 통해 Row Count를 잡고 필요한 줄만 체크
- file workbook을 쓸 때 숨김시트가 있고 잘못된 참조를 포함하는 경우 에러가 남(수식이 먹지 않는 경우도 생김) => 웬만하면 Excel Application Scope으로 진행
- Delete Row는 하면서 index가 바뀌기 때문에 마지막 인덱스부터 삭제해야 함
- BalaReva의 엑셀 시리즈에서 리스트를 넣어 row를 한번에 삭제하는 기능이 있으나, 리스트가 일정 크기 이상이되면 한번에 삭제가 되지 않음. 안 되면 Reverse해서 각각 지워야 함.
- Excel 데이터 서식을 바꿔야 하는 경우 BalaReva 엑셀시리즈 중 Change Cell Type으로 가능.
- 엑셀에서 날짜나 시간이 숫자로 읽히는 경우가 있는데, 그 경우 보통 OADate임.
- 엑셀에서 줄바꿈은 chr(10)으로 치환됨(environment.newline(chr(10)+chr(13))은 다른 줄바꿈임.)
- 엑셀에서의 줄바꿈을 변수로 불러서 쓰는 경우 \n으로 저장해놓고 chr(10)으로 치환해야 함
- 줄바꿈을 Replace 하려는 경우 chr(10)이나 chr(13)+chr(10)으로 쓰는 게 안전함. \n은 인식 못 하는 케이스가 있음.
- Excel Application Scope이 생각보다 불안함. 자주 에러나는 케이스의 경우 Try Catch로 감싸고 재시도 해줘야 되는 경우도 있음.
- Excel 필터에서 검색 기능을 쓸 때 (모두 선택)이나 '검색 결과 없음'은 팝업이 떠있다면 항상 존재함. 따라서 Continue On Error로 검색하는 것을 찾든 다른 형태로 체크해야 함.
- Excel 파일을 새로 만들 때 대괄호([ ])가 포함되면 생성되지 않음[기존 파일 이름에 대괄호가 포함되어 있어 읽는 경우는 문제가 없으나 생성하는 로직 중 문법에 대괄호가 포함된 것으로 보임]
- Excel Scope에서 Save Changes를 체크하는 경우 속도가 더 느리고 캐시 부담이 더 많이 감. 이걸 체크하면 다시 시도해야 될 때 파일을 초기화하기 어렵고, '다른 사용자가 파일을 사용 중입니다.' 에러가 더 자주 발생함. instancecaheperiod를 0으로 맞추고 save changes를 끈 다음 save workbook으로 처리하는 게 가장 깔끔
[원인을 정확히 특정할 수가 없으나 발생하면 동시다발적으로 발생하는 것으로 보아 환경적 요인으로 보임]
- Find는 Anchor를 쓸 때만 씀. 다른 용도는 사실 없다고 봐도 무방하지 않나 싶음.
- 셀에 색을 입히고 싶을 땐 Set Range Color를 씀. Color는 system.Drawing.Color.Red 식으로 지정.
- Read Cell을 했는데 Converter 관련 에러가 나오면 output을 String이 아닌 Object로 받으면 해결됨. [Uipath가 판단한 변수 타입이 아니어서 에러난 것이기 때문] (이와 관련해 구글시트에서는 값을 Object로 받도록 강제하기도 함]
- Read Range를 할 때 틀고정된 파일 등은 Starting Cell만 적으면 무한펜딩이 걸리는 케이스가 있음. 요청 파일을 받아서 진행하는 과제의 경우 웬만하면 Read Colmun으로 Row수를 알아내어 End Position까지 입력해주는 게 좋음
- 엑셀에서 함수식을 쓰는 경우 =A:A 가 =@A:A로 변하는 버전이 존재. 원인은 수식 언어가 업그레이드 되면서 레거시를 호환하기 위해 자동으로 삽입되는 것으로 파악하고 있으나 이 기능을 끄는 방법을 아직 발견하지 못 했음. Select Range로 셀을 선택하고 클립보드에서 붙이는 방식으로 개발하는 것이 좋을 듯. [Empty Field 같은 기능이 이상하게 먹히므로 del키 + 붙이기 형태로 send hotkey를 나눠쓰길 권장]
Exception
- Rethrow를 하면 안쪽에 있는 Try Catch에서 뱉은 Exception을 그대로 Throw 해줌[이중 Try Catch 구조일 때 유용]
- Invoke된 파일에서 Rethrow하면 인수값이 넘어오지 않음. Throw가 되더라도 특정 인수값을 넘겨야 한다면 Exception에만 담아두고 밖에서 변수값을 체크해야 함.
- 변수를 할당하고 만들 때는 일단 그것이 null일 수 있다는 가정을 해야 함(특히 Dictionary, List 같은 변수들 초기화 필수)
- Exception관련 초기화를 위해 프로그램을 끌 때 kill process가 간혹 안 먹히는 경우가 있는데 이를 강제로 종료하려면 Start Process에서 "taskkill.exe" / 파라미터로 "/f /im 종료하려는프로그램" 형태로 쓰고 뒤에 딜레이를 2~3초 정도 부여. (딜레이를 부여하는 이유는 바로 다음에 해당 프로그램을 켜면 Taskkill 중에 프로그램이 켜지면서 종료되는 케이스들이 있기 때문. 여러개 프로그램을 종료 하려는 경우 /im을 붙여가면서 추가하면 됨.)
-- taskkill 사용시 tray에 잔상이 남아있는 케이스가 있는데 그 경우 taskill /im explorer.exe /f를 한 후, start explorer.exe를 해주면 사라진다. 다만 메모장이나 탐색기 등 explorer의 자식 process도 함께 꺼진 후 다시 켜지기 때문에 그 부분은 감안할 필요가 있다. 대부분의 프로세스에서는 상관없을 것으로 보인다.
- Kill Process로 하면 간혹 안 먹고 살아있는 경우가 있다. 그 경우 확장자를 안 뺐을 확률이 큼. ex) chrome.exe 대신 chrome
File
- File Size 체크를 하는 경우 Int64 변수를 하나 만들어서 New System.IO.FileInfo("경로").Length 를 할당해 체크
- Folder의 경우 Folder Loop를 돌려도 되긴 하지만 Get Folder Info를 한 후 Output에 SizeInKB라는 메서드가 있음.
- Cloud Vision Activities를 쓰는 경우 Service Account Key보다 API Key를 쓰는 게 더 간단함(Service Account Key는 scope이 제대로 돼있지 않다는 오류가 뜨는데 정식 App 등록을 하고 프로젝트 승인을 받으라는 것으로 보임)
- 아래 소스는 reCaptcha를 회피하기 위해 만들어본 소스이나 실제로는 환경세팅으로 회피하는 게 더 적절(다만 구글 Cloud Vision API를 쓰는 2가지 버전의 소스가 있으니 참고
- Google Sheet의 Copy and Paste 기능은 제대로 동작 안 하는 것으로 보임(2021.05.24. 기준)
- Google Sheet는 데이터 Queue가 제한되어 있음(minute limit, quantity limit once). 따라서 데이터가 많다면 퍼포먼스가 좀 내려가긴 해도 잘라서 올려야 함. dt1을 써야 되는데 너무 많아서 5천줄씩 올린다라면 dt1.Rows.count mod 5000만큼 도는 루프를 만들어 올리고 나머지를 올림.
- dtContainer = dt1.ASEnumerable.Skip(5000*idx).Take(5000).CopyToDataTable 이런 형태로 자르고 Container를 전달하는 방식. 당연하게도 Queue limit 때문에 쓰는 거니 루프의 delay를 많이 주는 것이 안정적. [+ 고객사에 유료고객 전환을 요청.]
- 데이터 제한 이외에도 접근하려는 구글시트에서 수식을 계산하고 있는 경우, 접근하면 에러가 남. 그런 가능성이 있는 시트에 접근하는 경우 for each + try catch를 통해 방어로직 구현 필요.
If
- 21.10부터 Else IF가 추가됨. 기존에 가독성을 위해 IF A / IF A&B 같은 형태로 썼던 소스들이 간소화될 수 있게 됨. 특히 A&B에서 B가 A가 충족되지 않으면 에러가 나는 경우(예를 들어 isnot nothing이 성립되어야 count가 성립하는 식)에는 어쩔 수 없이 겹쳐지는 케이스들이 있었는데 그 케이스들도 가독성을 가져가면서 개발하기 쉽게 됨.
- 3항 연산자 사용 가능. If(조건식,True인 경우,False인 경우) => String 아닌 경우에도 사용 가능함. 특히 BusinessRule Exception 변수와 System Exception 변수를 구분하여 에러메세지를 작성하는 경우 if(eSysExp isnot nothing, "Unexpected Error", eBusinessExp.Message) 같은 형태로 많이 쓰게 됨.
List
- list에서 다른 list에 있는 값 제외하기 : lList1.Except(lList2).ToArray
-System.Collections.Generic.List<System.Int32>로 List를 만들고 New List(Of Int32) 같은 형태로 생성할 수도 있음[좀 더 일반적으로 쓰는 것으로 보임. 이걸로 해야 Invoke Method인 Sort나 Reverse 같은 걸 쓸 수 있음] => 이제 string[] 변수도 해당 기능이 생겼으므로 그냥 라이브러리의 취향차이라 생각하면 됨.
- List는 System.Collections.Generic.List 형태로 만들어야 다양하게 쓰긴 하지만 정말 Append 정도만 하고 싶다면 String[]도 괜찮음. 선언은 New List(Of Type)이 아니라 {}로 하면 됨.
- 폴더의 파일 리스트를 ","나 줄바꿈으로 Join하고 싶다면. String.Join(","+Environment.NewLine,lList1) 형태로 쓸 수 있음
- List에서 Sort를 쓰기 위해선 Linq를 쓰는 게 가장 무난. arrTest.OrderByDescending(Function(x) x).ToArray() // arrTest.OrderBy(Function(x) x).ToArray()
- Studio와 Attended는 AD 계정이 겹칠 수 없음. Unattended는 겹칠 수 있음. 이러한 차이는 인증방식의 차이에서 발생. Studio와 Attended는 오케와의 통신이 필수적이지 않기 떄문에 인증 시 AD계정을 PK로 가져감. Unattended는 어차피 오케와의 통신으로 컨트롤되기 때문에 Runtime 방식으로 인증되므로 AD계정이 겹쳐도 무관함. 따라서 특정 AD계정에서만 작동해야 하는 시스템에 대해 개발하는 경우 한 AD계정으로 동시개발을 할 수 없음. 다른 AD계정으로 개발할 수 있는 Studio를 세팅해야 함.
Loop
- Times 반복문 : For each에 enumerable.range(startindex,n)을 넣어 n회 수행(ex. (1,3)이면 1,2,3. (0,3)이면 0,1,2)
- loop를 2개 겹쳐 쓰면 item이라는 이름이 겹쳐 의도한 로직대로 수행되지 않을 수 있음(변수명 안 겹치게 잘 써야 함)
- Index를 담은 컬럼이 있다면 조건에 부합할 때 Index만 담아두었다가 삭제 등을 할 수 있음[굳이 루프 전체를 다시 훑으며 가지 않아도 됨]
- File in Folder loop를 쓰면 CurrentFile이라는 item을 쓸 수 있는데 Name 특성도 있고, FullName 특성도 있다. 파일을 컨트롤 해야 한다면 폴더루프를 쓰면 소스를 단축시킬 수도 있다. (원래는 file list get하고 그걸로 for each 돌려서 파일이름만 필요하면 따로 떼고 하는 식)
Orchestrator
- Studio와 Attended는 AD 계정이 겹칠 수 없음. Unattended는 겹칠 수 있음. 이러한 차이는 인증방식의 차이에서 발생. Studio와 Attended는 오케와의 통신이 필수적이지 않기 떄문에 인증 시 AD계정을 PK로 가져감. Unattended는 어차피 오케와의 통신으로 컨트롤되기 때문에 Runtime 방식으로 인증되므로 AD계정이 겹쳐도 무관함. 따라서 특정 AD계정에서만 작동해야 하는 시스템에 대해 개발하는 경우 한 AD계정으로 동시개발을 할 수 없음. 다른 AD계정으로 개발할 수 있는 Studio를 세팅해야 함. [특이한 케이스]
- 운영 VM을 복사하는 경우, 복사하는 시점에 해당 VM이 job을 실행하고 있는 경우, 복사된 VM에서도 job이 실행되고 곧바로 실패처리되어 같은 작업에 End Time이 찍히는 케이스가 있음. 다만 원본 VM에서는 계속 job이 정상 수행됨. [Process - device(robot)의 결합을 unique한 조합으로 보고 연결하기 때문에, 환경이 복사되는 경우 job의 로깅이 꼬일 수 있음]
- 스튜디오 구버전들에서 개발된 소스들은 1.0.7823.12009 같은 식으로 버전이 나오는데 이를 최신 스튜디오로 편집해서 다시 올리면 버전업이 제대로 되지 않을 수 있음. 이때는 버전을 올릴 때, 1.0.8000.20000 같은 식으로 숫자를 크게 하여 최신 버전으로 인식시키면 됨.
- Trigger를 걸 때 파라미터를 주면 Start Job으로 된 과제와 구분이 가능
- 특정 로컬에 패키지 초기 설치가 제대로 안 된 경우에는 시작되었습니다. 종료되었습니다. 하는 로그만 남는 케이스가 있음. 이 경우는 누겟폴더를 찾아 직접 주입을 해주자. [이런 경우는 외부와 폐쇄망이거나 새로 VM을 할당받아 세팅했을 때 간간히 일어난다]
- assistant에서 main(entry point)에 있는 argument를 넣을 수 있게 됐다. 다만 assistant에서 실행시키면 string 값이 null 되는 게 아니라 "" 빈 문자열로 들어가므로 체크 시 감안해야 한다.
Queue
- 'Queue'와 'Transaction'은 최초 상태에 대한 차이가 있다. Queue의 경우 Add 했을 때 프로세스의 과정 중 하나로 더해지기 때문에 New로 기록되지만 Transaction은 이미 한 프로세스를 시작하면서 동작하므로 In Progress로 기록된다.
- QueueItem은 Reference라는 Key를 할당할 수 있다. 해당 key를 통해 Filtering할 수도 있기 때문에 하나의 Queue Add하는 과제를 두고 Reference를 과제번호로 맞추면 하나의 Queue로 필터링하여 각각 다른 과제를 실행할 수도 있다.
Regex
- 정규표현식에서 자리수와 구성이 특정된 경우 ^구성조건$ 형태로 씀. (ex. 10자리 숫자로만 구성 => [^0-9]$) ^와 $를 쓰지 않으면 구성조건 앞뒤로 다른 문자, 숫자가 와도 True가 됨에 유의. 따라서 문자열에 특정 구성이 포함돼야 한다면 ^와 $를 빼고 쓰면 됨.
- Uipath에서 Regex를 할 때는 ^를 안에 넣어야 함. ex) ^[0-9]는 안 먹음. => [^0-9]
- Regex는 System.Text.RegularExpressions를 Import하고 쓰는 게 좋음.
- Regex.Replace(sTargetStr,"바꿀Regex표현형식","바꿀String값")으로 하면 string값에서 숫자만 걸러 낸다든가, 영어만 가져온다든가 할 수 있음
- System.Text.RegularExpressios.Regex.Replace(item.ToString,"\s+"," ") [빈 칸 여러 개 있으면 하나로 만들어 줌]
- Regex.replace(sInputString, "[^0-9|^a-z|^A-Z|^ㄱ-힣|^#|^&|^-|^_]","") [이모지 제거하고 DB에 넣기 위해 이렇게 만들었음]
Retry Scope
- Retry scope에서 가장 무난한 조건 값은 Is True인 것으로 보임[현재 check true라는 이름으로 변경됨]
- Retry scope을 대기시간만을 위해 쓰는 것은 적절하지 않음. Action에 뭐라도 Trigger가 있어야 함. (클릭이나 type into 같은 Action Trigger) 대기시간을 위해서라면 Timeout을 길게 늘이는 게 좋음.
- Retry Scope에 조건을 부여하지 않으면 모두 에러가 나지 않을 경우 그대로 진행함. 그러나 이는 Retry scope을 잘못 쓰고 있는 것. 보통 Action Trigger들이 에러가 난다는 건 페이지 로딩이 늦는 등의 문제기 때문에 Retry보단 Timeout으로 대체 가능함. 굳이 인식할 수 있는 정보를 잡지 않고 Retry하는 것은 세부 로깅만 잃어버리게 하므로 조건을 부여하지 않을 거라면 Retry를 이용한 방어로직을 쓰지 않도록 함.
- Retry Scope은 중간에 에러가 나도 Catch로 뛰지 않고 재시도함.[내부에 Catch가 포함돼있는 듯. 다만 exception이 제대로 떨어지지 않기 때문에, Retry Scope은 디버깅을 위해서라도 최대한 간단하게, 짧게 끊어서 써야 함.]
- Retry Scope은 에러가 나면 처음부터 다시 시작하기 때문에 init을 위해 일단 끝까지 진행돼야 하는 경우라면 continue on error를 설정해주자. [은근 이런 케이스가 많다]
SAP
- SAP Activity에서 Call T-Code를 쓰는 경우 /n을 치지 않아도 어디서든 이동함
- SAP 조회화면에서 Shell로 잡히는 곳의 레이아웃 선택 시 Select Menu Item으로 선택하면 한글 인코딩은 깨지는데 선택 가능해짐
- SAP에서 가장 많이 일어나는 문제는 권한 문제. 셀렉터가 잡히지 않거나 코드가 동작하지 않으면 대부분 관리자 권한으로 SAP이 켜졌을 확률이 높음.
ScreenShot
- [현재 테스트 중] Take Screenshot을 전체화면으로 찍을 때 간간히 에러가 나기도 하는데(RDP 세션이 물려있다든가 혹은 절전모드, 로그오프 등이 진행된 상태), Clipping을 아예 잡아주면 완화. 이벤트 뷰어에서도 핸들링 관련 에러가 나는 걸 보면 Windows에서 해상도(Resolution) 관련 값을 주지 못해 발생하는 것으로 보임.
Script
- Inject JS에서 크롬기준 Jquery는 안 먹음. 보통 console창에서 먹는 JS는 먹는데 간간히 안 먹는 사이트도 있음. (Click 같은 걸 하려면 ID값을 추천. JS에서 ClassName은 click 메서드 자체가 없는 듯)
String
- 문자열 구성은 String.Format(텍스트 변수, 파라미터1, 파라미터2, ....) 으로 하는 게 가장 깔끔해 보임. 파라미터가 들어갈 곳을 {0}, {1}, {2}, ... 로 쓰고 각각 할당. 파라미터들 대신에 리스트 변수를 써도 순서대로 들어감.
- String.Format안에 중괄호 자체를 쓰고 싶은 경우 {{, }} 식으로 Escape 해야 함
(예를 들어, 숫자가 아닌 것들은 다 없애고 싶다 => Regex.Replace(sTest,"[^0-9]","") 식으로 쓸 수 있음)
[Regex가 바로 안 되는 경우 System.Text.RegularExpression.Regex~~ 로 쓰거나 Arguments 옆에 Import 탭에서 System.Text.RegularExpression를 추가하면 됨]
- Get Password의 경우 소스가 옮겨가면 오리지날 문자열을 다시 적어줘야 함
다시 안 적으면 "get password: 키를 지정된 상태에서 사용하기에 부적합합니다." 라는 메세지가 뜸.
Task
- 실행되고 있는 특정 program을 가져오려면 system.Diagnostics.Process.GetProcessesByName("chrome") 식으로 가져올 수 있다. (return은 process[]) count가 0보다 크냐로 보면 지금 실행되고 있는지 아닌지도 체크할 수 있다.
Uipath Tool
- Uipath에서 간혹 Drag & Drop이 안 먹히는 경우가 있음. 그 경우 ESC를 누르면 해결됨.
[뭔가를 처리하다가 끊긴 게 제대로 Exception 처리가 안 돼서 일어나는 현상인 듯]
- 스니펫 소환 => Ctrl+Shift+J
- 변수의 Scope을 잘 이용하면 시퀀스만 복사해서 비슷한 류의 코드를 빠르게 짤 수 있음
- 여러 케이스를 동시에 판단해야 되는 경우 Parallel을 이용해 각각 Exist 등의 Activity를 넣고 해당 변수를 Parallel Exit의 조건으로 작성. bTest1 Or bTest2 Or bTest3
- Parallel을 응용하면 Dialog의 Time-out도 줄 수 있음[Dialog를 켜놓고 click의 Before Delay를 조정]
- Xplatform도 아닌데 안 잡히는 경우, Plug-In을 살펴봐야 함. 보통 크롬의 경우는 잘 알려져 있으나 Java 프로그램 같은 경우도 플러그인이 깔려있는지 체크 필요. 일반적으로 잘 잡힘.
Xaml
- Invoke시 인수 대소문자 구별해야 함. 구별 안 하면 null값이 됨.
- 파일 소스를 열 수 없고 특정 위치를 명시하는 에러가 뜬다면 xml이 꼬인 것. 해당 위치에 있는 Argument를 다른 Argument들의 형태와 맞춰주고 조정하다 보면 다시 살리기 가능함. 원인은 아직 불명이고 간헐적으로 나타남. (자주 발생한 개발자나 Device에서 더 자주 발생하는 것으로 보아 특정 개발자의 습관에 관련되지 않았을까 추정)
Zip
- Compress(Zip)의 경우 System Activities를 업데이트 하면 기본 Activities가 존재
- Files로 해놓고 폴더와 파일을 같이 입력해도 잘 압축됨(Files와 Folder가 나뉘어 있는 이유는 폴더 버튼을 눌렀을 때 어디까지 보이게 할 건지를 체크하고자 했던 것으로 보임. 다만 User에겐 별 의미가 없는 듯)
과제 개발 시 Combo box는 다양하게 나타나지만 결국 값을 입력하기 위한 input element이다.
Select Item으로 선택되지 않는 combox의 값을 select하는 방법을 3가지로 나눠봤다.
[Select Item은 무조건 먼저 해보길 권장한다. 리스트형인 모든 element에 이것 먼저 해보도록 하자]
1. (Click) + Type into
- Type into는 옵션을 어떻게 선택하느냐에 따라 기능이 깡패기 때문에 AlterIfDisable, Empty Filed, Simulate Type을 선택하면 그냥 선택하는 거든, 쓰는 게 막혀있는 거든 웬만해선 다 적어버린다.
- inner text를 주입하는 수준이기 때문에 딱 봐도 안 될 거 같다면 이 방식부터 쓰길 권장한다.
- 다만 몇몇 콤보박스의 경우 click을 Trigger로 값이 로딩되는 경우가 있으므로 click 추가 후 after delay를 주기 바란다.
2. (click) + Set Text
- 태그에 inner text를 주입하는 원리에 가까움
- 다만 Type into는 키별 주입을 한다면 Set text는 String값 자체를 한번에 주입하는 느낌[그래봤자 비슷하다]
- 1번을 우선 해보고 안 될 때 시도
3. (click) + click
- 될 거 같은데? 하는 콤보박스라면 이거부터 시도하길 바람
- 뒤쪽의 클릭은 simulate type을 걸어두어야 스크롤이 생겨도 문제가 없음
=> 다만 제대로 submit 되는지 필히 체크해야 함. simulate 방식 특성상 값이 들어간 것처럼만 보이고 실제론 container에 들어가지 않았다든가 하는 경우가 있을 수 있음. 다만 한번 제대로 성공한 걸 확인했다면, 그 후론 헛클릭, 헛타이핑하지 않음. (simulate를 쓰는 이유. Default나 SendwindowsMsg는 그런 케이스가 1000번하면 대략 3~4번쯤 존재)
- 다른 방식은 값이 없어도 에러가 안 나기도 하는데, click은 높은 확률로 없으면 에러가 남 [정합성 검사 유리]
- 스크롤을 해야만 클릭이 되는 케이스도 있으므로 그 경우는 스크롤을 하면서 에러가 나지 않을 때까지 반복시키는 형태로 구성해야 함.
4. click + double click
- 클릭을 제대로 했음에도 불구하고 값이 default로 다시 바뀌는 현상(iframe환경)
- 클릭 후 더블클릭(simulate)하여 해결되었다고 함(before delay도 추가)
- 추정으로는 Selector가 실제 submit되는 값의 바깥쪽으로 잡혀서 제대로 Trigger가 되지 않은 것으로 보임
- 이 경우 첫번째 클릭이 일종의 그 dropdown list를 선택하는 형태가 되므로 default로 변경되는 것도 설명할 수 있음