Friday, December 9, 2011

Webdriver - File upload (IE Driver)

Webdriver - File upload (IE Driver)

To upload file I have used different ways including (Auto It V3), but not successful.

It was really amazing when "SendKeys" method is able to open the Browse window dialog, browse the file and open the file. I have not seen the level of sophistication even in the HP QTP. Hats-off to the Webdriver team.

Attaching webdriver code and file upload control HTML.

driver.findElement(By.id("ctl00_CphePurchase_FileUpload1")).sendKeys("C:\\Selenium Files\\Signature.jpg");

I was curious to look at the "SendKeys" code that is handling the file upload, after digging the IE driver came across following code.

        static unsigned int WINAPI SendKeysCommandHandler::SetFileValue(void *file_data) {
                FileNameData* data = reinterpret_cast(file_data);
                ::Sleep(100);
                HWND ie_main_window_handle = data->main;
                HWND dialog_window_handle = ::GetLastActivePopup(ie_main_window_handle);

                int max_wait = 10;
                while ((dialog_window_handle == ie_main_window_handle) && --max_wait) {
                        ::Sleep(100);
                        dialog_window_handle = ::GetLastActivePopup(ie_main_window_handle);
                }

                if (!dialog_window_handle || (dialog_window_handle == ie_main_window_handle)) {
                        // No dialog directly owned by the top-level window.
                        // Look for a dialog belonging to the same process as
                        // the IE server window. This isn't perfect, but it's
                        // all we have for now.
                        max_wait = 10;
                        while ((dialog_window_handle == ie_main_window_handle) && --max_wait) {
                                ProcessWindowInfo process_win_info;
                                process_win_info.dwProcessId = data->ieProcId;
                                ::EnumWindows(&BrowserFactory::FindDialogWindowForProcess, (LPARAM)&process_win_info);
                                if (process_win_info.hwndBrowser != NULL) {
                                        dialog_window_handle = process_win_info.hwndBrowser;
                                }
                        }
                }

                if (!dialog_window_handle || (dialog_window_handle == ie_main_window_handle)) {
                        LOG(WARN) << "No dialog found";
                        return false;
                }

                return SendKeysToFileUploadAlert(dialog_window_handle, data->text);
        }

        static bool SendKeysToFileUploadAlert(HWND dialog_window_handle, const wchar_t* value) 
        {
                HWND edit_field_window_handle = NULL;
                int maxWait = 10;
                while (!edit_field_window_handle && --maxWait) {
                        wait(200);
                        edit_field_window_handle = dialog_window_handle;
                        for (int i = 1; fileDialogNames[i]; ++i) {
                                edit_field_window_handle = getChildWindow(edit_field_window_handle, fileDialogNames[i]);
                        }
                }

                if (edit_field_window_handle) {
                        // Attempt to set the value, looping until we succeed.
                        const wchar_t* filename = value;
                        size_t expected = wcslen(filename);
                        size_t curr = 0;

                        while (expected != curr) {
                                ::SendMessage(edit_field_window_handle, WM_SETTEXT, 0, (LPARAM) filename);
                                wait(1000);
                                curr = ::SendMessage(edit_field_window_handle, WM_GETTEXTLENGTH, 0, 0);
                        }

                        for (int i = 0; i < 10000; i++) 
                        {
                                HWND open_window_handle = ::FindWindowExW(dialog_window_handle, NULL, L"Button", L"&Open");
                                if (open_window_handle) {
                                        LRESULT total = 0;
                                        total += ::SendMessage(open_window_handle, WM_LBUTTONDOWN, 0, 0);
                                        total += ::SendMessage(open_window_handle, WM_LBUTTONUP, 0, 0);

                                        if (total == 0)
                                        {
                                                return true;
                                        }

                                        wait(500);
                                }
                        }

                        LOG(ERROR) << "Unable to set value of file input dialog";
                        return false;
                }

                LOG(WARN) << "No edit found";
                return false;
        }

---

2 comments:

  1. Hi,
    I tried the below code snippet to run through the File Upload in FF9 but uncessful. I would appreciate your help. Below code browser.findElement(By.id("ctl00_mainContentPlaceHolder_SlickUpload1_fileSelector_html_file0")).sendKeys("G:\\Software\\Video format\\sample_iTunes.mov");

    ReplyDelete
  2. Hello Riy,
    It work only for few file upload controls, if this doesn't need to use AutoItv3.

    ReplyDelete