Esempio n. 1
0
class Ali(object):
    """docstring for Ali"""
    def __init__(self, email):
        super(Ali, self).__init__()
        # email here as the broswer profile dir name
        self.b = Chrome(user_data_dir=os.path.join(USER_DATA_DIR, valid_path(email)))
        self.search_url = 'http://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&CatId=&SearchText='
        self.manage_product_url = 'http://hz.productposting.alibaba.com/product/manage_products.htm'
        self.copy_product_url = 'http://hz.productposting.alibaba.com/product/post_product_interface.htm?from=manage&import_product_id='
        self.keywords_url = 'http://hz.my.data.alibaba.com/industry/keywords.htm'
        self.db = MongoClient()[db_name(email)]
        self.key_words_table = self.db.key_words_table
        self.products_table = self.db.products_table
        self.product_name_table = self.db.product_name_table

    def js_fill(self, selector, value):
        js = "document.querySelector('%s').value = '%s'" % (selector, value)
        self.b.execute_script(js)
    
    def select(self, _id, value):
        xp = '//select[@id="%s"]/option[normalize-space(text())="%s"]' % (_id, value)
        self.b.find_by_xpath(xp).first.click()

    def find_and_select(self, element, value):
        select = element.find_by_tag('select')
        if select:
            self.select(select.first['id'], value)

    def login(self, email, password):
        self.b.visit(VIP_URL)

        if not self.b.status_code.is_success():
            return False

        username = self.b.find_by_css('#xloginPassportId').first
        if username.value != email:
            self.js_fill('#xloginPassportId', email)

        pwd = self.b.find_by_css('#xloginPasswordId').first
        if pwd.value != password:
            self.js_fill('#xloginPasswordId', password)

        self.b.find_by_css('#signInButton').first.click()
        return True

    def get_auth_code(self):
        self.b.find_by_css('input[class="get-authcode-btn"]').first.click()

    def input_auth_code(self, auth_code):
        self.b.find_by_css('input[class="auth-code"]').first.fill(auth_code)
        self.b.find_by_css('input[class="validate-submit-btn submit-btn"]').first.click()

    def upload_product(self, product_id):
        p = self.products_table.find_one({'_id':ObjectId(product_id)})

        sc = {'search_keyword':p['key_words']}
        count = self.key_words_table.find(sc).count()
        if count < 3:
            self.collect_key_words(p['key_words'])

        self.b.visit('http://hz.productposting.alibaba.com/product/posting.htm')
        # clear the ui mask
        if self.b.find_by_css('div[class="ui-mask"]'):
            self.b.find_by_css('a[class="ui-window-close"]').first.click()

        # fill the category form
        self.js_fill('input[name=keyword]', p['category_name'])
        self.b.find_by_css('button[type=submit]').first.click()
        self.b.find_by_css('.current').first.double_click()
        # fill the product info page
        self.fill_product_detail(p)
        print 'tuwenmin----------------------------------'

    def browser_select_file(self, name):
        file_path = os.path.join(IMAGE_PATH, name, name + '.jpg')
        select_file(file_path)

    def copy_to_new_product(self, aid):
        url = self.copy_product_url + aid
        p = self.products_table.find_one({'aid':aid})
        self.b.visit(url)
        self.b.find_by_css('#yuigen0').first.click()
        self.browser_select_file(p['product_name_path'])
        self.fill_three_key_words(p['key_words'])
        self.fill_new_product_name(p['product_name'])
        submit_btn = self.b.find_by_css('#submitFormBtnA').first
        submit_btn.mouse_over()
        while not self.b.find_by_css('#withPicStatic').first.visible:
            time.sleep(1)
        submit_btn.click()
        if self.b.is_element_present_by_css('#display-new', 5):
            return True

    def get_product_id(self, pid):
        if 'products_manage' not in self.b.url:
            self.b.visit(self.manage_product_url)
        
        self.b.find_link_by_partial_text("ALL (").first.click()
        p = self.products_table.find_one({'_id':ObjectId(pid)})
        product_name = p['product_name']
        first_page = self.b.find_link_by_text('1')

        if first_page:
            first_page.click()

        aid = self.get_product_aid_recursively(product_name, pid)
        return aid

    def get_product_aid_recursively(self, product_name, product_id):
        while self.b.is_element_not_present_by_css('.product-item-title'):
            time.sleep(1)
          
        nonesence = 'http://hz.productposting.alibaba.com/product/product_detail.htm?id='
        a = self.b.find_link_by_text(product_name)
        if a:
            aid = a.first['href'].replace(nonesence, '').strip()
            self.products_table.update({'_id':ObjectId(product_id)}, {'$set':{'aid': aid}})
            return aid
        else:
            if self.b.find_by_css('.ui-pagination-disabled.ui-pagination-next'):
                return None
            else:
                self.b.find_by_css('.ui-pagination-next').first.click()
                self.get_product_aid_recursively(product_name, product_id)
        return None

    def collect_key_words(self, keywords):
        if self.b.url != self.keywords_url:
            self.b.visit(self.keywords_url)

        if self.b.is_element_present_by_css('#J-search-keywords'):
            self.b.find_by_css('#J-search-keywords').first.fill(keywords)
            self.b.find_by_css('#J-search-trigger').first.click()
        else:
            return 0

        counter = 0
        while self.b.is_element_present_by_css('.J-keyword-line'):
            one_page_keywords = self.b.find_by_css('.J-keyword-line')
            for line in one_page_keywords:
                tds = line.find_by_tag('td')
                counter += 1
                data = {
                    'search_keyword': keywords,
                    'keyword': tds[0].text,
                    'company_cnt': tds[1].text,
                    'showwin_cnt': tds[2].text,
                    'hotness': tds[3].text
                }
                self.key_words_table.insert(data)
            if counter > 60:
                return counter
            #save key words
            if self.b.is_element_present_by_css('.ui-pagination-next.ui-pagination-disabled'):
                return counter
            else:
                self.b.find_by_css('.ui-pagination-next').first.click()
        return counter

    def fill_new_product_name(self, product_name):
        condition = {'product_name': product_name}
        count = self.products_table.find(condition).count()
        if count == 0:
            names = collect_names(product_name)
            data = []
            for name in names:
                data.append({'product_name':product_name, 'variant':name})
            self.product_name_table.insert(data)

        variant_name = self.product_name_table.find_one(condition).sort('used_count')
        # self.b.find_by_css('#productName').first.fill(variant_name['variant'])
        self.js_fill('#productName', variant_name['variant'])
        self.product_name_table.update(variant_name, {'$inc':{'used_count':1}})

    def fill_three_key_words(self, search_keyword):
        condition = {'search_keyword':search_keyword.lower()}
        kws = self.key_words_table.find(condition).sort('used_count').limit(3)
        keywords = []
        for kw in kws:
            keywords.append(kw['keyword'])
            self.key_words_table.update(kw, {'$inc':{'used_count':1}})

        # self.b.find_by_css('#productKeyword').first.fill(keywords[0])
        # self.b.find_by_css('#keywords2').first.fill(keywords[1])
        # self.b.find_by_css('#keywords3').first.fill(keywords[2])
        self.js_fill('#productKeyword', keywords[0])
        self.js_fill('#keywords2', keywords[1])
        self.js_fill('#keywords3', keywords[2])

    def fill_product_detail(self, bse):
        while self.b.is_element_not_present_by_css('h1[class="ui-form-guide"]'):
            time.sleep(1)
        # product name
        self.js_fill('#productName', bse['product_name'])
        # three key words
        self.fill_three_key_words(bse['key_words'])
        # listing description
        self.b.find_by_css('#summary').first.fill(bse['summary'])
        # product detail
        name = self.b.find_by_css('.attr-title')
        option = self.b.find_by_css('.attribute-table-td')
        pi = bse['attrs']

        for i, n in enumerate(name):
            text = n.text
            if text == 'Type:':
                pi.pop('Type:')

            elif text == 'Computerized:':
                self.find_and_select(option[i], pi.pop('Computerized:', 'No'))

            elif text == 'Warranty:':
                option[i].find_by_tag('input').first.fill(pi.pop('Warranty:', 'NULL'))

            elif text == 'Power(W):':
                option[i].find_by_tag('input').first.fill(pi.pop('Power(W):', 'w'))

            elif text == 'After-sales Service Provided:':
                default_service = 'No overseas service provided'
                self.b.find_option_by_text(pi.pop('After-sales Service Provided:', default_service)).first.click()

            elif text == 'Certification:':
                option[i].find_by_tag('input').first.fill(pi.pop('Certification:', 'NULL'))

            elif text == 'Weight:':
                option[i].find_by_tag('input').first.fill(pi.pop('Weight:', 'kg'))

            elif text == 'Dimension(L*W*H):':
                option[i].find_by_tag('input').first.fill(pi.pop('Dimension(L*W*H):', 'mm'))

            elif text == 'Model Number:':
                option[i].find_by_tag('input').first.fill(pi.pop('Model Number:', 'YASON'))

            elif text == 'Brand Name:':
                option[i].find_by_tag('input').first.fill(pi.pop('Brand Name:', 'YASON'))

            elif text == 'Power:':
                power = pi.pop('Power:', None)
                if power:
                    option[i].find_by_tag('input').first.fill(power)

            elif text == 'Voltage:':
                option[i].find_by_tag('input').first.fill(pi.pop('Voltage:', '220v or 110v or customized'))

            elif text == 'Condition:':
                self.find_and_select(option[i], 'New')

            elif text == 'Place of Origin:':
                self.b.select('contryValue', 'CN-China (Mainland)')
                self.b.select('provinceValue', 'GUA-Guangdong')

            elif text == 'Driven Type:':
                dt = pi.pop('Driven Type:', 'Manual')
                checked = self.choose_option(option[i].find_by_tag('select').first, dt)
                if not checked:
                    option[i].find_by_tag('input').first.fill(dt.capitalize())

            elif text == 'Application:':
                self.check_boxes(option[i], pi.pop('Application:', 'Chemical,Medical'))

            elif text == 'Packaging Type:':
                self.check_boxes(option[i], pi.pop('Packaging Type:', 'Cartons'))

            elif text == 'Packaging Material:':
                self.check_boxes(option[i], pi.pop('Packaging Material:', 'Paper,Wood'))

            elif text == 'Automatic Grade:':
                ag = pi.pop('Automatic Grade:', 'Semi-Automatic')
                checked = self.choose_option(option[i].find_by_tag('select').first, ag)
                if not checked:
                    option[i].find_by_tag('input').first.fill(ag.capitalize())

        if pi:
            add_button = self.b.find_by_css('#copyActionButton').first
            # there is a default one, so minus it
            for i in range(len(pi) - 1):
                add_button.click()
            attrs = self.b.find_by_css('.custom-attr-item')
            for att in attrs:
                n, v = pi.popitem()
                inputs = att.find_by_tag('input')
                inputs[0].fill(n)
                inputs[1].fill(v)


        # trade information NO WHOLESALE right now
        no_wholesale = self.b.find_by_css('#setDefaultBtn')
        if no_wholesale and no_wholesale.first.visible:
            no_wholesale.first.click()

        ti = bse['trade_information']
        # 20 is number for Set/Sets
        self.select('minOrderUnit', ti.pop('minOrderUnit', 'Set/Sets'))
        self.select('supplyUnit', ti.pop('supplyUnit', 'Set/Sets'))
        self.select('priceUnit', ti.pop('priceUnit', 'Set'))
        self.select('moneyType', ti.pop('moneyType', 'USD'))
        self.select('supplyPeriod', ti.pop('supplyPeriod', 'Week'))
        self.check_payment_method(ti.pop('paymentMethod'))
        for k, v in ti.iteritems():
            self.js_fill('#' + k, v)

        self.b.find_by_css('#packagingDesc').first.fill(bse['pd']['Packaging Detail:'])
        self.b.find_by_css('#consignmentTerm').first.fill(bse['pd']['Delivery Detail:'])
        # rich descriptions
        js = "tinyMCE.activeEditor.setContent('%s')" % bse['rich_descs']
        self.b.execute_script(js)
        # select product main image
        self.b.find_by_css('#yuigen0').first.click()
        self.browser_select_file(bse['product_name_path'])

    def check_payment_method(self, values):
        values = values.split(',')
        values = [v.strip() for v in values]
        checked_values = []
        check_boxes = {}
        for i in range(1, 7):
            box = self.b.find_by_id('paymentMethod' + str(i)).first
            check_boxes[box.value] = box

        for value in values:
            if value in check_boxes:
                check_boxes[value].check()
                checked_values.append(value)
        # if all checked then no other needs to be added
        if len(values) == len(checked_values):
            return

        left_values = set(values) - set(checked_values)
        self.b.find_by_css('#paymentMethodOther').check()
        other = ', '.join([v.capitalize() for v in left_values])
        self.b.find_by_css('#paymentMethodOtherDesc').first.fill(other)

    def choose_option(self, select, value):
        options = select.find_by_tag('option')
        for option in options:
            if option.text == value:
                option.check()
                return True
        # check Other option before return
        for option in options:
            if option.text == 'Other':
                option.check()
        return False

    def check_boxes(self, checkbox, values):
        values = values.split(',')
        values = [v.strip() for v in values]
        options = checkbox.find_by_tag('input')
        other_check_box = None
        checked_values = []

        for option in options:
            true_value = option.value.split('-')[-1]
            if true_value == 'Other':
                other_check_box = option
            elif true_value in values:
                checked_values.append(true_value)
                option.check()
        # deal with other
        if len(values) == len(checked_values):
            return

        left_values = set(values) - set(checked_values)
        other_check_box.check()
        other = ', '.join([v.capitalize() for v in left_values])
        checkbox.find_by_tag('input')[-1].fill(other)

    def quit(self):
        try:
            self.b.quit()
        except Exception, e:
            print e
Esempio n. 2
0
class TestCase(unittest.TestCase):
    """
    Base class for all test cases
    """

    def __init__(self, *args, **kwargs):
        self._logger = None
        self.proxy = swt.proxy
        self._browser_capabilities = swt.desired_browser

        if self._browser_capabilities["browserName"] == "internet explorer":
            self._finetuneIE()

        super(TestCase, self).__init__(*args, **kwargs)


    def log(self, message):
        """
        Log message to stdout

        :param message: Text to be send to stdout
        """
        self._logger.write(message)


    def take_screenshot(self):
        """
        Takes screenshot.
        """

        filename = self.id()
        filename += "-on-" + self.stringifyBrowserCapabilities("_")
        filename += "-at-" + datetime.datetime.now().isoformat()
        filename += ".png"
        self.driver.get_screenshot_as_file(os.path.normpath(swt.config.SCREENSHOTS_DIR) + os.sep + filename)


    def stringifyBrowserCapabilities(self, delimiter=","):
        """
        Returns browser info as string

        :param delimiter: Character to be used as properties delimiter
        """

        return self._browser_capabilities["browserName"] + delimiter + self._browser_capabilities["version"] + delimiter + self._browser_capabilities["platform"]

    def setUp(self):
        """
        Code to be executed before each test
        """

        self.driver = WebDriver(
            "http://{0}:{1}/wd/hub".format(swt.config.ADDRESS, swt.config.SELENIUM_SERVER_PORT),
            self._browser_capabilities,
            proxy=self.proxy.selenium_proxy()
        )
        swt.active_driver = self.driver


    def run(self, result=None):
        try:
            super(TestCase, self).run(result)
        except:
            self.tearDown()


    def tearDown(self):
        """
        Code to be executed after each test
        """

        self._checkJSErrors()
        swt.active_driver = None
        self.driver.quit()


    def retry(self):
        """
        Will append this test at the end of test suite.
        """

        swt.retried_tests.append(self.id())
        swt.desired_browser = self._browser_capabilities
        test = swt.test_loader.load_tests_from_name(self.id())
        swt.test_suite.addTests(test)


    def _checkJSErrors(self):
        """
        Checks if "console.getData()" JS command returns some error. If so, the test will fail.
        """

        js_error = False
        console_data = []
        try:
            console_data = self.driver.execute_script("return console.getData()")
        except:
            pass

        if console_data:
            for item in console_data:
                if item["type"] == "error":
                    js_error = item
                    break

        # fail test if there is any JS error in the console
        if js_error:
            self.fail("An JS error has occured on the page: " + json.dumps(js_error))


    def _finetuneIE(self):
        """
        Some special settings for IE to make the browser more stable.
        """

        # start IE in private mode to prevent storing cookies
        self._browser_capabilities["ie.forceCreateProcessApi"] = 1
        self._browser_capabilities["ie.browserCommandLineSwitches"] = "-private"

        # seems not reliable. More testing needed.
        #self._browser_capabilities["ie.usePerProcessProxy"] = True

        # Too slow. Private mode is probably better solution for cache and cookie cleaning
        #self._browser_capabilities["ie.ensureCleanSession"] = True

        # IE seems to be more stable with this option
        self._browser_capabilities["ie.setProxyByServer"] = True

        # IE8 hack to prevent "...click on the element was not scrolled into the viewport" error
        if self._browser_capabilities["version"] == "8.0":
            self._browser_capabilities["elementScrollBehavior"] = 1