diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 9a408430e7..d29f0a9c97 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -507,26 +507,6 @@ def run_ui_tests(context, app, headless=False): formatted_command = command.format(site_env=site_env, password_env=password_env, run_or_open=run_or_open) frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True) -@click.command('run-setup-wizard-ui-test') -@click.option('--app', help="App to run tests on, leave blank for all apps") -@click.option('--profile', is_flag=True, default=False) -@pass_context -def run_setup_wizard_ui_test(context, app=None, profile=False): - "Run setup wizard UI test" - import frappe.test_runner - - site = get_site(context) - frappe.init(site=site) - frappe.connect() - - ret = frappe.test_runner.run_setup_wizard_ui_test(app=app, verbose=context.verbose, - profile=profile) - if len(ret.failures) == 0 and len(ret.errors) == 0: - ret = 0 - - if os.environ.get('CI'): - sys.exit(ret) - @click.command('serve') @click.option('--port', default=8000) @click.option('--profile', is_flag=True, default=False) @@ -752,7 +732,6 @@ commands = [ reset_perms, run_tests, run_ui_tests, - run_setup_wizard_ui_test, serve, set_config, show_config, diff --git a/frappe/test_runner.py b/frappe/test_runner.py index 76140e442c..be2e909dd0 100644 --- a/frappe/test_runner.py +++ b/frappe/test_runner.py @@ -36,6 +36,9 @@ def main(app=None, module=None, doctype=None, verbose=False, tests=(), with open(frappe.get_app_path(app, doctype_list_path), 'r') as f: doctype = f.read().strip().splitlines() + if ui_tests: + print("Selenium testing has been deprecated\nUse bench --site {site_name} run-ui-tests for Cypress tests") + xmloutput_fh = None if junit_xml_output: xmloutput_fh = open(junit_xml_output, 'w') @@ -170,21 +173,6 @@ def run_tests_for_module(module, verbose=False, tests=(), profile=False): return _run_unittest(module, verbose=verbose, tests=tests, profile=profile) -def run_setup_wizard_ui_test(app=None, verbose=False, profile=False): - '''Run setup wizard UI test using test_test_runner''' - frappe.flags.run_setup_wizard_ui_test = 1 - return run_ui_tests(app=app, test=None, verbose=verbose, profile=profile) - -def run_ui_tests(app=None, test=None, test_list=None, verbose=False, profile=False): - '''Run a single unit test for UI using test_test_runner''' - module = importlib.import_module('frappe.tests.ui.test_test_runner') - frappe.flags.ui_test_app = app - if test_list: - frappe.flags.ui_test_list = test_list - else: - frappe.flags.ui_test_path = test - return _run_unittest(module, verbose=verbose, tests=(), profile=profile) - def _run_unittest(modules, verbose=False, tests=(), profile=False): test_suite = unittest.TestSuite() diff --git a/frappe/tests/test_frappeoauth2client.py b/frappe/tests/test_frappeoauth2client.py deleted file mode 100644 index ebf09adf6d..0000000000 --- a/frappe/tests/test_frappeoauth2client.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt -from __future__ import unicode_literals - -import unittest, frappe, requests, time -from frappe.test_runner import make_test_records -from frappe.utils.selenium_testdriver import TestDriver -from six.moves.urllib.parse import urlparse -from frappe.frappeclient import FrappeOAuth2Client - -class TestFrappeOAuth2Client(unittest.TestCase): - def setUp(self): - self.driver = TestDriver() - make_test_records("OAuth Client") - make_test_records("User") - self.client_id = frappe.get_all("OAuth Client", fields=["*"])[0].get("client_id") - - # Set Frappe server URL reqired for id_token generation - try: - frappe_login_key = frappe.get_doc("Social Login Key", "frappe") - except frappe.DoesNotExistError: - frappe_login_key = frappe.new_doc("Social Login Key") - frappe_login_key.get_social_login_provider("Frappe", initialize=True) - frappe_login_key.base_url = "http://localhost:8000" - frappe_login_key.save() - - def test_insert_note(self): - - # Go to Authorize url - self.driver.get( - "api/method/frappe.integrations.oauth2.authorize?client_id=" + - self.client_id + - "&scope=all%20openid&response_type=code&redirect_uri=http%3A%2F%2Flocalhost" - ) - - time.sleep(2) - - # Login - username = self.driver.find("#login_email")[0] - username.send_keys("test@example.com") - - password = self.driver.find("#login_password")[0] - password.send_keys("Eastern_43A1W") - - sign_in = self.driver.find(".btn-login")[0] - sign_in.submit() - - time.sleep(2) - - # Allow access to resource - allow = self.driver.find("#allow")[0] - allow.click() - - time.sleep(2) - - # Get authorization code from redirected URL - auth_code = urlparse(self.driver.driver.current_url).query.split("=")[1] - - payload = "grant_type=authorization_code&code=" - payload += auth_code - payload += "&redirect_uri=http%3A%2F%2Flocalhost&client_id=" - payload += self.client_id - - headers = {'content-type':'application/x-www-form-urlencoded'} - - # Request for bearer token - token_response = requests.post( frappe.get_site_config().host_name + - "/api/method/frappe.integrations.oauth2.get_token", data=payload, headers=headers) - - # Parse bearer token json - bearer_token = token_response.json() - client = FrappeOAuth2Client(frappe.get_site_config().host_name, bearer_token.get("access_token")) - - notes = [ - {"doctype": "Note", "title": "Sing", "public": True}, - {"doctype": "Note", "title": "a", "public": True}, - {"doctype": "Note", "title": "Song", "public": True}, - {"doctype": "Note", "title": "of", "public": True}, - {"doctype": "Note", "title": "sixpence", "public": True} - ] - - for note in notes: - client.insert(note) - - self.assertTrue(len(frappe.get_all("Note")) == 5) diff --git a/frappe/tests/ui/__init__.py b/frappe/tests/ui/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frappe/tests/ui/data/test_lib.js b/frappe/tests/ui/data/test_lib.js deleted file mode 100644 index 0fbbc2b748..0000000000 --- a/frappe/tests/ui/data/test_lib.js +++ /dev/null @@ -1,249 +0,0 @@ -frappe.tests = { - data: {}, - make: function(doctype, data) { - let dialog_is_active = () => { - return ( - cur_dialog && (!cur_frm || cur_frm.doc.doctype != doctype) - ); - }; - return frappe.run_serially([ - () => frappe.set_route('List', doctype), - () => frappe.new_doc(doctype), - () => { - if (frappe.quick_entry) { - frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(); - return frappe.timeout(1); - } else { - let root_node; - if (cur_tree) { - for (const key in cur_tree.nodes) { - if (cur_tree.nodes[key].parent_label && cur_tree.nodes[key].expandable) { - root_node = cur_tree.nodes[key].label; - break; - } - } - } - if (root_node){ - frappe.tests.open_add_child_dialog(root_node); - return frappe.timeout(1); - } - } - }, - () => { - if(dialog_is_active()) { - return frappe.tests.set_dialog_values(cur_dialog, data); - } else { - return frappe.tests.set_form_values(cur_frm, data); - } - }, - - () => { - if(dialog_is_active()) { - return cur_dialog.get_primary_btn().click(); - } else { - return frappe.quick_entry ? frappe.quick_entry.insert() : cur_frm.save(); - } - } - ]); - }, - open_add_child_dialog: (root_node) => { - frappe.tests.click_link(root_node); - frappe.timeout(1); - frappe.tests.click_button('Add Child'); - }, - set_form_values: (frm, data) => { - let tasks = []; - - data.forEach(item => { - for (let key in item) { - let task = () => { - let value = item[key]; - if ($.isArray(value)) { - return frappe.tests.set_grid_values(frm, key, value); - } else { - // single value - return frm.set_value(key, value); - } - }; - tasks.push(task); - tasks.push(frappe.after_ajax); - tasks.push(() => frappe.timeout(0.4)); - } - }); - - // set values - return frappe.run_serially(tasks); - - }, - set_dialog_values: (dialog, data) => { - let tasks = []; - - data.forEach(item => { - for (let key in item) { - let task = () => { - let value = item[key]; - return dialog.set_value(key, value); - }; - tasks.push(task); - tasks.push(frappe.after_ajax); - tasks.push(() => frappe.timeout(0.4)); - } - }); - - return frappe.run_serially(tasks); - }, - set_grid_values: (frm, key, value) => { - // set value in grid - let grid = frm.get_field(key).grid; - grid.remove_all(); - - let grid_row_tasks = []; - - // build tasks for each row - value.forEach(d => { - grid_row_tasks.push(() => { - - let grid_value_tasks = []; - grid_value_tasks.push(() => grid.add_new_row()); - grid_value_tasks.push(() => grid.get_row(-1).toggle_view(true)); - grid_value_tasks.push(() => frappe.timeout(0.5)); - - // build tasks to set each row value - d.forEach(child_value => { - for (let child_key in child_value) { - grid_value_tasks.push(() => { - let grid_row = grid.get_row(-1); - return frappe.model.set_value(grid_row.doc.doctype, - grid_row.doc.name, child_key, child_value[child_key]); - }); - grid_value_tasks.push(frappe.after_ajax); - grid_value_tasks.push(() => frappe.timeout(0.4)); - } - }); - - return frappe.run_serially(grid_value_tasks); - }); - }); - return frappe.run_serially(grid_row_tasks); - }, - setup_doctype: (doctype, data) => { - return frappe.run_serially([ - () => frappe.set_route('List', doctype), - () => frappe.timeout(1), - () => { - frappe.tests.data[doctype] = []; - let expected = Object.keys(data); - cur_list.data.forEach((d) => { - frappe.tests.data[doctype].push(d.name); - if(expected.indexOf(d.name) !== -1) { - expected[expected.indexOf(d.name)] = null; - } - }); - - let tasks = []; - - expected.forEach(function(d) { - if(d) { - tasks.push(() => frappe.tests.make(doctype, - data[d])); - } - }); - - return frappe.run_serially(tasks); - }]); - }, - click_page_head_item: (text) => { - // Method to items present on the page header like New, Save, Delete etc. - let possible_texts = ["New", "Delete", "Save", "Yes"]; - return frappe.run_serially([ - () => { - if (text == "Menu"){ - $(`span.menu-btn-group-label:contains('Menu'):visible`).click(); - } else if (text == "Refresh") { - $(`.btn-secondary:contains('Refresh'):visible`).click(); - } else if (possible_texts.includes(text)) { - $(`.btn-primary:contains("${text}"):visible`).click(); - } - }, - () => frappe.timeout(1) - ]); - }, - click_dropdown_item: (text) => { - // Method to click dropdown elements - return frappe.run_serially([ - () => { - let li = $(`.dropdown-menu li:contains("${text}"):visible`).get(0); - $(li).find(`a`).click(); - }, - () => frappe.timeout(1) - ]); - }, - click_desktop_icon: (text) => { - // Method to click the desktop icons on the Desk, by their name - return frappe.run_serially([ - () => $("#icon-grid > div > div.app-icon[title="+text+"]").click(), - () => frappe.timeout(1) - ]); - }, - is_visible: (text, tag='a') => { - // Method to check the visibility of an element - return $(`${tag}:contains("${text}")`).is(`:visible`); - }, - /** - * Clicks a button on a form. - * @param {String} text - The button's text - * @return {frappe.timeout} - * @throws will throw an exception if a matching visible button is not found - */ - click_button: function(text) { - let element = $(`.btn:contains("${text}"):visible`); - if(!element.length) { - throw `did not find any button containing ${text}`; - } - element.click(); - return frappe.timeout(0.5); - }, - /** - * Clicks a link on a form. - * @param {String} text - The text of the link to be clicked - * @return {frappe.timeout} - * @throws will throw an exception if a link with the given text is not found - */ - click_link: function(text) { - let element = $(`a:contains("${text}"):visible`); - if(!element.length) { - throw `did not find any link containing ${text}`; - } - element.get(0).click(); - return frappe.timeout(0.5); - }, - /** - * Sets the given control to the value given. - * @param {String} fieldname - The Doctype's field name - * @param {String} value - The value the control should be changed to - * @return {frappe.timeout} - * @throws will throw an exception if the field is not found or is not visible - */ - set_control: function(fieldname, value) { - let control = $(`.form-control[data-fieldname="${fieldname}"]:visible`); - if(!control.length) { - throw `did not find any control with fieldname ${fieldname}`; - } - control.val(value).trigger('change'); - return frappe.timeout(0.5); - }, - /** - * Checks if given field is disabled. - * @param {String} fieldname - The Doctype field name - * @return {Boolean} true if condition is met - * @throws will throw an exception if the field is not found or is not a form control - */ - is_disabled_field: function(fieldname){ - let control = $(`.form-control[data-fieldname="${fieldname}"]:disabled`); - if(!control.length) { - throw `did not find any control with fieldname ${fieldname}`; - } else { - return true; - } - } -}; \ No newline at end of file diff --git a/frappe/tests/ui/test_calendar_view.js b/frappe/tests/ui/test_calendar_view.js deleted file mode 100644 index 914f6174da..0000000000 --- a/frappe/tests/ui/test_calendar_view.js +++ /dev/null @@ -1,79 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Calendar View Tests", function(assert) { - assert.expect(3); - let done = assert.async(); - let random_text = frappe.utils.get_random(3); - let today = frappe.datetime.get_today()+" 16:20:35"; //arbitrary value taken to prevent cases like 12a for 12:00am and 12h to 24h conversion - let visible_time = () => { - // Method to return the start-time (hours) of the event visible - return $('.fc-time').text().split('p')[0]; // 'p' because the arbitrary time is pm - }; - let event_title_text = () => { - // Method to return the title of the event visible - return $('.fc-title:visible').text(); - }; - - frappe.run_serially([ - // create 2 events, one private, one public - () => frappe.tests.make("Event", [ - {subject: random_text + ':Pri'}, - {starts_on: today}, - {event_type: 'Private'} - ]), - - () => frappe.timeout(1), - - () => frappe.tests.make("Event", [ - {subject: random_text + ':Pub'}, - {starts_on: today}, - {event_type: 'Public'} - ]), - - () => frappe.timeout(1), - - // Goto Calendar view - () => frappe.set_route(["List", "Event", "Calendar"]), - - // clear filter - () => cur_list.filter_area.remove('event_type'), - () => frappe.timeout(2), - // Check if event is created - () => { - // Check if the event exists and if its title matches with the one created - assert.ok(event_title_text().includes(random_text + ':Pri'), - "Event title verified"); - }, - - // check filter - () => cur_list.filter_area.add('Event', 'event_type', '=', 'Public'), - () => frappe.timeout(1), - () => { - // private event should be hidden - assert.notOk(event_title_text().includes(random_text + ':Pri'), - "Event title verified"); - }, - - // Delete event - // Goto Calendar view - () => frappe.set_route(["List", "Event", "Calendar"]), - () => frappe.timeout(1), - // delete event - () => frappe.click_link(random_text + ':Pub'), - () => { - frappe.tests.click_page_head_item('Menu'); - frappe.tests.click_dropdown_item('Delete'); - }, - () => frappe.timeout(0.5), - () => frappe.click_button('Yes'), - () => frappe.timeout(2), - () => frappe.set_route(["List", "Event", "Calendar"]), - () => frappe.click_button("Refresh"), - () => frappe.timeout(1), - - // Check if event is deleted - () => assert.notOk(event_title_text().includes(random_text + ':Pub'), - "Event deleted"), - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_control_geolocation.js b/frappe/tests/ui/test_control_geolocation.js deleted file mode 100644 index 0e3bedda26..0000000000 --- a/frappe/tests/ui/test_control_geolocation.js +++ /dev/null @@ -1,39 +0,0 @@ -QUnit.module('controls'); - -QUnit.test("Test ControlGeolocation", function(assert) { - assert.expect(1); - - const random_name = frappe.utils.get_random(3).toLowerCase(); - - let done = assert.async(); - - // geolocation alert dialog suppressed (only secure origins or localhost allowed) - window.alert = function() { - console.log.apply(console, arguments); //eslint-disable-line - }; - - frappe.run_serially([ - () => { - return frappe.tests.make('Custom Field', [ - {dt: 'ToDo'}, - {fieldtype: 'Geolocation'}, - {label: random_name}, - ]); - }, - () => frappe.set_route('List', 'ToDo'), - () => frappe.new_doc('ToDo'), - () => { - if (frappe.quick_entry) - { - frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(); - return frappe.timeout(1); - } - }, - () => { - const control = $(`.frappe-control[data-fieldname="${random_name}"]`); - - return assert.ok(control.data('fieldtype') === 'Geolocation'); - }, - () => done() - ]); -}); diff --git a/frappe/tests/ui/test_control_html.js b/frappe/tests/ui/test_control_html.js deleted file mode 100644 index 0cb70cc4fd..0000000000 --- a/frappe/tests/ui/test_control_html.js +++ /dev/null @@ -1,57 +0,0 @@ -QUnit.module('controls'); - -QUnit.test("Test ControlHTML", function(assert) { - assert.expect(3); - const random_name = frappe.utils.get_random(3).toLowerCase(); - - let done = assert.async(); - - frappe.run_serially([ - () => { - return frappe.tests.make('Custom Field', [ - {dt: 'ToDo'}, - {fieldtype: 'HTML'}, - {label: random_name}, - {options: '

Test

'} - ]); - }, - () => { - return frappe.tests.make('Custom Field', [ - {dt: 'ToDo'}, - {fieldtype: 'HTML'}, - {label: random_name + "_template"}, - {options: '

Test {{ doc.status }}

'} - ]); - }, - () => frappe.set_route('List', 'ToDo'), - () => frappe.new_doc('ToDo'), - () => { - if (frappe.quick_entry) - { - frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(); - return frappe.timeout(1); - } - }, - () => { - const control = $(`.frappe-control[data-fieldname="${random_name}"]`)[0]; - - return assert.ok(control.innerHTML === '

Test

'); - }, - () => { - const control = $(`.frappe-control[data-fieldname="${random_name}_template"]`)[0]; - // refresh input must be called independently - cur_frm.get_field(`${random_name}_template`).refresh_input(); - - return assert.ok(control.innerHTML === '

Test Open

'); - }, - () => frappe.tests.set_control("status", "Closed"), - () => frappe.timeout(1), - () => { - const control = $(`.frappe-control[data-fieldname="${random_name}_template"]`)[0]; - // refresh input must be called independently - cur_frm.get_field(`${random_name}_template`).refresh_input(); - return assert.ok(control.innerHTML === '

Test Closed

'); - }, - () => done() - ]); -}); diff --git a/frappe/tests/ui/test_kanban/test_kanban_column.js b/frappe/tests/ui/test_kanban/test_kanban_column.js deleted file mode 100644 index 0c4593a8dd..0000000000 --- a/frappe/tests/ui/test_kanban/test_kanban_column.js +++ /dev/null @@ -1,31 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test: Setting column colour [Kanban view]", function(assert) { - assert.expect(3); - let done = assert.async(); - function get_column(name, colour) { - return ('.kanban-column:contains('+name+')>div>div>ul>li>div.'+colour); - } - - frappe.run_serially([ - () => frappe.set_route("List", "ToDo", "Kanban", "Kanban test"), - () => frappe.timeout(1), - () => assert.deepEqual(["List", "ToDo", "Kanban", "Kanban test"], frappe.get_route(), - "Kanban view opened successfully."), - () => { - // set colour for columns - $(get_column('High', "red")).click(); - $(get_column('Medium', "green")).click(); - $(get_column('Low', "yellow")).click(); - }, - () => frappe.timeout(1), - () => { - //check if different colours are set - assert.equal($('.red > span')[0].innerText, 'High', - "Colour is set for kanban column."); - assert.equal($('.green > span')[0].innerText, 'Medium', - "Different colour is set for other column."); - }, - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_kanban/test_kanban_creation.js b/frappe/tests/ui/test_kanban/test_kanban_creation.js deleted file mode 100644 index 3e1afbefdf..0000000000 --- a/frappe/tests/ui/test_kanban/test_kanban_creation.js +++ /dev/null @@ -1,34 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test: Creation [Kanban view]", function(assert) { - assert.expect(2); - let done = assert.async(); - - const board_name = 'Kanban test'; - - frappe.run_serially([ - () => frappe.set_route("List", "ToDo", "List"), - // wait for cur_list to initialize - () => cur_list.init(), - // click kanban in side bar - () => frappe.tests.click_link('Kanban'), - () => frappe.tests.click_link('New Kanban Board'), - () => frappe.timeout(0.5), - // create new kanban - () => { - assert.equal(cur_dialog.title, 'New Kanban Board', - "Dialog for new kanban opened."); - cur_dialog.set_value('board_name', board_name); - cur_dialog.set_value('field_name', 'Priority'); - }, - () => frappe.timeout(0.5), - () => cur_dialog.get_primary_btn().click(), - () => frappe.timeout(1), - () => frappe.set_route("List", "Kanban Board", "List"), - () => frappe.timeout(0.5), - // check in kanban list if new kanban is created - () => assert.equal(cur_list.data[0].name, board_name, - "Added kanban is visible in kanban list."), - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_kanban/test_kanban_filters.js b/frappe/tests/ui/test_kanban/test_kanban_filters.js deleted file mode 100644 index 5e9af9f0fa..0000000000 --- a/frappe/tests/ui/test_kanban/test_kanban_filters.js +++ /dev/null @@ -1,27 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test: Filters [Kanban view]", function(assert) { - assert.expect(3); - let done = assert.async(); - - frappe.run_serially([ - () => frappe.set_route("List", "ToDo", "Kanban", "Kanban test"), - () => frappe.timeout(1), - () => { - assert.deepEqual(["List", "ToDo", "Kanban", "Kanban test"], frappe.get_route(), - "Kanban view opened successfully."); - }, - // set filter values - () => cur_list.filter_area.add('ToDo', 'priority', '=', 'Low'), - () => frappe.timeout(1), - () => cur_list.page.btn_secondary.click(), - () => frappe.timeout(1), - () => { - assert.equal(cur_list.data[0].priority, 'Low', - 'visible element has low priority'); - let non_low_items = cur_list.data.filter(d => d.priority != 'Low'); - assert.equal(non_low_items.length, 0, 'No item without low priority'); - }, - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_kanban/test_kanban_view.js b/frappe/tests/ui/test_kanban/test_kanban_view.js deleted file mode 100644 index 4ed9597cf0..0000000000 --- a/frappe/tests/ui/test_kanban/test_kanban_view.js +++ /dev/null @@ -1,29 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test: Kanban view", function(assert) { - assert.expect(4); - let done = assert.async(); - - frappe.run_serially([ - () => frappe.set_route("List", "ToDo", "List"), - // calculate number of element in list - () => frappe.timeout(1), - () => frappe.set_route("List", "ToDo", "Kanban", "Kanban test"), - () => frappe.timeout(2), - () => { - assert.equal('Kanban', cur_list.view_name, - "Current view is kanban."); - assert.equal("Kanban test", cur_list.page_title, - "Kanban view opened successfully."); - // check if all elements are visible in kanban view - const $high_priority_cards = - $('.kanban-column[data-column-value="High"] .kanban-card-wrapper'); - const $low_priority_cards = - $('.kanban-column[data-column-value="Low"] .kanban-card-wrapper'); - - assert.equal($high_priority_cards.length, 1); - assert.equal($low_priority_cards.length, 1); - }, - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_linked_with.js b/frappe/tests/ui/test_linked_with.js deleted file mode 100644 index aeaced2d19..0000000000 --- a/frappe/tests/ui/test_linked_with.js +++ /dev/null @@ -1,19 +0,0 @@ -QUnit.module('form'); - -QUnit.test("Test Linked With", function(assert) { - assert.expect(2); - const done = assert.async(); - - frappe.run_serially([ - () => frappe.set_route('Form', 'Module Def', 'Contacts'), - () => frappe.tests.click_page_head_item('Menu'), - () => frappe.tests.click_dropdown_item('Links'), - () => frappe.timeout(4), - () => { - assert.equal(cur_dialog.title, 'Linked With', 'Linked with dialog is opened'); - const link_tables_count = cur_dialog.$wrapper.find('.list-item-table').length; - assert.equal(link_tables_count, 2, 'Two DocTypes are linked with Contacts'); - }, - done - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_list/test_list_filter.js b/frappe/tests/ui/test_list/test_list_filter.js deleted file mode 100644 index 059122f0c0..0000000000 --- a/frappe/tests/ui/test_list/test_list_filter.js +++ /dev/null @@ -1,39 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test list filters", function(assert) { - assert.expect(3); - let done = assert.async(); - - frappe.run_serially([ - () => { - return frappe.tests.make('ToDo', [ - {description: 'low priority'}, - {priority: 'Low'} - ]); - }, - () => { - return frappe.tests.make('ToDo', [ - {description: 'high priority'}, - {priority: 'High'} - ]); - }, - () => frappe.set_route('List', 'ToDo', 'List'), - () => frappe.timeout(0.5), - () => { - assert.deepEqual(['List', 'ToDo', 'List'], frappe.get_route(), - "List opened successfully."); - //set filter values - return frappe.set_control('priority', 'Low'); - }, - () => frappe.timeout(0.5), - () => cur_list.page.btn_secondary.click(), - () => frappe.timeout(1), - () => { - assert.equal(cur_list.data[0].priority, 'Low', - 'visible element has low priority'); - let non_low_items = cur_list.data.filter(d => d.priority != 'Low'); - assert.equal(non_low_items.length, 0, 'no item without low priority'); - }, - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_list/test_list_paging.js b/frappe/tests/ui/test_list/test_list_paging.js deleted file mode 100644 index b760a11370..0000000000 --- a/frappe/tests/ui/test_list/test_list_paging.js +++ /dev/null @@ -1,25 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test paging in list view", function(assert) { - assert.expect(5); - let done = assert.async(); - - frappe.run_serially([ - () => frappe.set_route('List', 'DocType'), - () => frappe.timeout(0.5), - () => assert.deepEqual(['List', 'DocType', 'List'], frappe.get_route(), - "List opened successfully."), - //check elements less then page length [20 in this case] - () => assert.equal(cur_list.data.length, 20, 'show 20 items'), - () => frappe.click_button('More'), - () => frappe.timeout(2), - () => assert.equal(cur_list.data.length, 40, 'show more items'), - () => frappe.tests.click_button('100'), - () => frappe.timeout(2), - () => assert.ok(cur_list.data.length > 40, 'show 100 items'), - () => frappe.tests.click_button('20'), - () => frappe.timeout(2), - () => assert.equal(cur_list.data.length, 20, 'show 20 items again'), - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_list_count.js b/frappe/tests/ui/test_list_count.js deleted file mode 100644 index 31f73964d2..0000000000 --- a/frappe/tests/ui/test_list_count.js +++ /dev/null @@ -1,33 +0,0 @@ -QUnit.module('Setup'); - -QUnit.test("Test List Count", function(assert) { - assert.expect(3); - const done = assert.async(); - - frappe.run_serially([ - () => frappe.set_route('List', 'DocType'), - () => frappe.timeout(0.5), - () => { - let count = $('.list-count').text().split(' ')[0]; - assert.equal(cur_list.data.length, count, "Correct Count"); - }, - - () => frappe.timeout(1), - () => cur_list.filter_area.add('Doctype', 'module', '=', 'Desk'), - () => frappe.click_button('Refresh'), - () => { - let count = $('.list-count').text().split(' ')[0]; - assert.equal(cur_list.data.length, count, "Correct Count"); - }, - - () => cur_list.filter_area.clear(), - () => frappe.timeout(1), - () => { - cur_list.filter_area.add('DocField', 'fieldname', 'like', 'owner'); - let count = $('.list-count').text().split(' ')[0]; - assert.equal(cur_list.data.length, count, "Correct Count"); - }, - - done - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_module_view.js b/frappe/tests/ui/test_module_view.js deleted file mode 100644 index 7340945b29..0000000000 --- a/frappe/tests/ui/test_module_view.js +++ /dev/null @@ -1,41 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test modules view", function(assert) { - assert.expect(4); - let done = assert.async(); - - frappe.run_serially([ - - //click Document Share Report in Permissions section [Report] - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.click_link('Document Share Report'), - () => assert.deepEqual(frappe.get_route(), ["List", "DocShare", "Report", "Document Share Report"], - 'document share report'), - - //click Print Setting in Printing section [Form] - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.click_link('Print Settings'), - () => assert.deepEqual(frappe.get_route(), ["Form", "Print Settings"], - 'print settings'), - - //click Workflow Action in Workflow section [List] - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.click_link('Workflow Action'), - () => assert.deepEqual(frappe.get_route(), ["List", "Workflow Action", "List"], - 'workflow action'), - - //click Workflow Action in Workflow section [List] - () => frappe.set_route("modules"), - () => frappe.timeout(0.5), - () => frappe.click_link('Tools'), - () => frappe.timeout(0.5), - () => frappe.click_link('To Do'), - () => assert.deepEqual(frappe.get_route(), ["List", "ToDo", "List"], - 'todo list'), - - () => done() - ]); -}); diff --git a/frappe/tests/ui/test_number_format.js b/frappe/tests/ui/test_number_format.js deleted file mode 100644 index 2bca7d92f6..0000000000 --- a/frappe/tests/ui/test_number_format.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// MIT License. See license.txt - -QUnit.module("Number Formatting"); - -QUnit.test("#,###.##", function(assert) { - assert.equal(format_number(100, "#,###.##"), "100.00"); - assert.equal(format_number(1000, "#,###.##"), "1,000.00"); - assert.equal(format_number(10000, "#,###.##"), "10,000.00"); - assert.equal(format_number(1000000, "#,###.##"), "1,000,000.00"); - assert.equal(format_number(1000000.345, "#,###.##"), "1,000,000.35"); -}); - -QUnit.test("#,##,###.##", function(assert) { - assert.equal(format_number(100, "#,##,###.##"), "100.00"); - assert.equal(format_number(1000, "#,##,###.##"), "1,000.00"); - assert.equal(format_number(10000, "#,##,###.##"), "10,000.00"); - assert.equal(format_number(1000000, "#,##,###.##"), "10,00,000.00"); - assert.equal(format_number(1000000.341, "#,##,###.##"), "10,00,000.34"); - assert.equal(format_number(10000000.341, "#,##,###.##"), "1,00,00,000.34"); -}); - -QUnit.test("#.###,##", function(assert) { - assert.equal(format_number(100, "#.###,##"), "100,00"); - assert.equal(format_number(1000, "#.###,##"), "1.000,00"); - assert.equal(format_number(10000, "#.###,##"), "10.000,00"); - assert.equal(format_number(1000000, "#.###,##"), "1.000.000,00"); - assert.equal(format_number(1000000.345, "#.###,##"), "1.000.000,35"); -}); - -QUnit.test("#.###", function(assert) { - assert.equal(format_number(100, "#.###"), "100"); - assert.equal(format_number(1000, "#.###"), "1.000"); - assert.equal(format_number(10000, "#.###"), "10.000"); - assert.equal(format_number(-100000, "#.###"), "-100.000"); - assert.equal(format_number(1000000, "#.###"), "1.000.000"); - assert.equal(format_number(1000000.345, "#.###"), "1.000.000"); -}); \ No newline at end of file diff --git a/frappe/tests/ui/test_social_login_key_buttons.py b/frappe/tests/ui/test_social_login_key_buttons.py deleted file mode 100644 index 376d4139e4..0000000000 --- a/frappe/tests/ui/test_social_login_key_buttons.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt -from __future__ import unicode_literals - -import unittest, frappe, time -from frappe.utils.selenium_testdriver import TestDriver - -class TestSocialLoginKeyButtons(unittest.TestCase): - def setUp(self): - try: - frappe_login_key = frappe.get_doc("Social Login Key", "frappe") - except frappe.DoesNotExistError: - frappe_login_key = frappe.new_doc("Social Login Key") - frappe_login_key.get_social_login_provider("Frappe", initialize=True) - frappe_login_key.base_url = "http://localhost:8000" - frappe_login_key.enable_social_login = 1 - frappe_login_key.client_id = "test_client_id" - frappe_login_key.client_secret = "test_client_secret" - frappe_login_key.save() - - self.driver = TestDriver() - - def test_login_buttons(self): - - # Go to Login Page - self.driver.get("login") - - time.sleep(2) - frappe_social_login = self.driver.find(".btn-frappe") - self.assertTrue(len(frappe_social_login) > 0) - - def tearDown(self): - self.driver.close() diff --git a/frappe/tests/ui/test_test_runner.py b/frappe/tests/ui/test_test_runner.py deleted file mode 100644 index 8b207cd02d..0000000000 --- a/frappe/tests/ui/test_test_runner.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import print_function, unicode_literals -from frappe.utils.selenium_testdriver import TestDriver -import unittest, os, frappe, time - -class TestTestRunner(unittest.TestCase): - def test_test_runner(self): - if frappe.flags.run_setup_wizard_ui_test: - for setup_wizard_test in frappe.get_hooks("setup_wizard_test"): - passed = frappe.get_attr(setup_wizard_test)() - self.assertTrue(passed) - return - - driver = TestDriver() - frappe.db.set_default('in_selenium', '1') - driver.login() - for test in get_tests(): - if test.startswith('#'): - continue - - timeout = 60 - passed = False - if '#' in test: - test, comment = test.split('#') - test = test.strip() - if comment.strip()=='long': - timeout = 300 - - print('Running {0}...'.format(test)) - - frappe.db.set_value('Test Runner', None, 'module_path', test) - frappe.db.commit() - driver.refresh() - driver.set_route('Form', 'Test Runner') - try: - driver.click_primary_action() - driver.wait_for('#frappe-qunit-done', timeout=timeout) - console = driver.get_console() - passed = 'Tests Passed' in console - finally: - console = driver.get_console() - passed = 'Test Passed' in console - if frappe.flags.tests_verbose or not passed: - for line in console: - print(line) - print('-' * 40) - else: - self.assertTrue(passed) - time.sleep(1) - frappe.db.set_default('in_selenium', None) - driver.close() - -def get_tests(): - '''Get tests base on flag''' - frappe.db.set_value('Test Runner', None, 'app', frappe.flags.ui_test_app or '') - - if frappe.flags.ui_test_list: - # list of tests - return get_tests_for(test_list=frappe.flags.ui_test_list) - elif frappe.flags.ui_test_path: - # specific test - return (frappe.flags.ui_test_path,) - elif frappe.flags.ui_test_app: - # specific app - return get_tests_for(frappe.flags.ui_test_app) - else: - # all apps - tests = [] - for app in frappe.get_installed_apps(): - tests.extend(get_tests_for(app)) - return tests - -def get_tests_for(app=None, test_list=None): - tests = [] - if test_list: - # Get all tests from a particular txt file - app, test_list = test_list.split(os.path.sep, 1) - tests_path = frappe.get_app_path(app, test_list) - else: - # Get all tests for a particular app - tests_path = frappe.get_app_path(app, 'tests', 'ui', 'tests.txt') - if os.path.exists(tests_path): - with open(tests_path, 'r') as fileobj: - tests = fileobj.read().strip().splitlines() - return tests diff --git a/frappe/tests/ui/test_todo.py b/frappe/tests/ui/test_todo.py deleted file mode 100644 index bb367e7851..0000000000 --- a/frappe/tests/ui/test_todo.py +++ /dev/null @@ -1,50 +0,0 @@ -from __future__ import print_function, unicode_literals -from frappe.utils.selenium_testdriver import TestDriver -import unittest -import time, os - -class TestToDo(unittest.TestCase): - def setUp(self): - self.driver = TestDriver() - - def test_todo(self): - self.driver.login() - - # list view - self.driver.set_route('List', 'ToDo') - - time.sleep(2) - - # new - self.driver.click_primary_action() - - time.sleep(2) - - # set input - self.driver.set_text_editor('description', 'hello') - - # save - self.driver.click_modal_primary_action() - - time.sleep(2) - - # refresh - self.driver.click_secondary_action() - - time.sleep(2) - - result_list = self.driver.get_visible_element('.result-list') - first_element_text = (result_list - .find_element_by_css_selector('.list-item') - .find_element_by_css_selector('.list-id').text) - - # if os.environ.get('CI'): - # # we don't run this test in Travis as it always fails - # # reinforcing why we use Unit Testing instead of integration - # # testing - # return - - self.assertTrue('hello' in first_element_text) - - def tearDown(self): - self.driver.close() diff --git a/frappe/tests/ui/tests.txt b/frappe/tests/ui/tests.txt deleted file mode 100644 index 2fcbf64851..0000000000 --- a/frappe/tests/ui/tests.txt +++ /dev/null @@ -1,20 +0,0 @@ -frappe/tests/ui/test_number_format.js -frappe/tests/ui/test_list/test_list_filter.js -frappe/tests/ui/test_list/test_list_paging.js -frappe/tests/ui/test_module_view.js -frappe/tests/ui/test_calendar_view.js -frappe/tests/ui/test_kanban/test_kanban_creation.js -frappe/tests/ui/test_kanban/test_kanban_view.js -frappe/tests/ui/test_kanban/test_kanban_filters.js -frappe/tests/ui/test_kanban/test_kanban_column.js -frappe/core/doctype/report/test_query_report.js -frappe/tests/ui/test_linked_with.js -frappe/custom/doctype/customize_form/test_customize_form.js -frappe/desk/doctype/event/test_event.js -frappe/tests/ui/test_control_html.js -frappe/tests/ui/test_control_geolocation.js -frappe/core/doctype/role_profile/test_role_profile.js -frappe/core/doctype/user/test_user_with_role_profile.js -frappe/tests/ui/test_list_count.js -frappe/workflow/doctype/workflow/tests/test_workflow_create.js -frappe/workflow/doctype/workflow/tests/test_workflow_test.js \ No newline at end of file diff --git a/frappe/utils/selenium_testdriver.py b/frappe/utils/selenium_testdriver.py deleted file mode 100644 index cde0e5cb45..0000000000 --- a/frappe/utils/selenium_testdriver.py +++ /dev/null @@ -1,299 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -from __future__ import unicode_literals, print_function - -from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -#from selenium.webdriver.support.select import Select -from selenium.webdriver.support import expected_conditions as EC -#from selenium.common.exceptions import TimeoutException -from selenium.webdriver.chrome.options import Options -from selenium.webdriver.common.desired_capabilities import DesiredCapabilities - -import time -import signal -import os, sys -import frappe -from ast import literal_eval - -class TestDriver(object): - def __init__(self, port=None): - self.port = port or frappe.get_site_config().webserver_port or '8000' - - chrome_options = Options() - capabilities = DesiredCapabilities.CHROME - - if os.environ.get('CI'): - self.host = 'localhost' - else: - self.host = frappe.local.site - - # enable browser logging - capabilities['loggingPrefs'] = {'browser':'ALL'} - - chrome_options.add_argument('--no-sandbox') - chrome_options.add_argument('--start-maximized') - self.driver = webdriver.Chrome(chrome_options=chrome_options, - desired_capabilities=capabilities, port=9515) - - # self.driver.set_window_size(1080,800) - self.cur_route = None - self.logged_in = False - - @property - def localhost(self): - return "http://{host}:{port}".format(host=self.host, port=self.port) - - def get(self, url): - return self.driver.get(os.path.join(self.localhost, url)) - - def start(self): - def signal_handler(signal, frame): - self.close() - sys.exit(0) - signal.signal(signal.SIGINT, signal_handler) - - def refresh(self): - self.driver.refresh() - - def close(self): - if self.driver: - self.driver.quit() - self.driver = None - - def login(self, wait_for_id="#page-desktop", animate=0, scroll_offset=0): - if self.logged_in: - return - self.get('login') - self.wait_for("#login_email") - self.set_input("#login_email", "Administrator") - self.set_input("#login_password", "admin") - self.click('.btn-login', animate=animate, offset=scroll_offset) - self.wait_for(wait_for_id) - self.logged_in = True - - def set_input(self, selector, text, key=None, xpath=None): - elem = self.find(selector, xpath=xpath)[0] - elem.clear() - elem.send_keys(text) - if key: - time.sleep(0.5) - elem.send_keys(key) - time.sleep(0.2) - - def set_field(self, fieldname, text): - elem = self.wait_for(xpath='//input[@data-fieldname="{0}"]'.format(fieldname)) - time.sleep(0.2) - elem.send_keys(text) - - def set_select(self, fieldname, text): - elem = self.wait_for(xpath='//select[@data-fieldname="{0}"]'.format(fieldname)) - time.sleep(0.2) - elem.send_keys(text) - - def set_multicheck(self, fieldname, values): - for value in values: - path = '//div[@data-fieldname="{0}"]//span[@data-unit="{1}"]'.format(fieldname, value) - elem = self.wait_for(xpath=path) - time.sleep(0.2) - elem.click() - - def set_text_editor(self, fieldname, text): - elem = self.wait_for(xpath='//div[@data-fieldname="{0}"]//div[@contenteditable="true"]'.format(fieldname)) - time.sleep(0.2) - elem.send_keys(text) - - def find(self, selector=None, everywhere=False, xpath=None): - if xpath: - return self.driver.find_elements_by_xpath(xpath) - else: - if self.cur_route and not everywhere: - selector = self.cur_route + " " + selector - return self.driver.find_elements_by_css_selector(selector) - - def wait_for(self, selector=None, everywhere=False, timeout=20, xpath=None, for_invisible=False): - if self.cur_route and not everywhere: - selector = self.cur_route + " " + selector - - time.sleep(0.5) - - if selector: - _by = By.CSS_SELECTOR - if xpath: - _by = By.XPATH - selector = xpath - - try: - if not for_invisible: - elem = self.get_wait(timeout).until( - EC.presence_of_element_located((_by, selector))) - else: - elem = self.get_wait(timeout).until( - EC.invisibility_of_element_located((_by, selector))) - return elem - except Exception as e: - # body = self.driver.find_element_by_id('body_div') - # print(body.get_attribute('innerHTML')) - self.print_console() - raise e - - def wait_for_invisible(self, selector=None, everywhere=False, timeout=20, xpath=None): - self.wait_for(selector, everywhere, timeout, xpath, True) - - def get_console(self): - out = [] - for entry in self.driver.get_log('browser'): - source, line_no, message = entry.get('message').split(' ', 2) - - if message and message[0] in ('"', "'"): - # message is a quoted/escaped string - message = literal_eval(message) - - out.append(source + ' ' + line_no) - out.append(message) - out.append('-'*40) - - return out - - def print_console(self): - for line in self.get_console(): - print(line) - - def get_wait(self, timeout=20): - return WebDriverWait(self.driver, timeout) - - def scroll_to(self, selector, animate=0, offset=0): - self.execute_script("frappe.ui.scroll('{0}', {1}, {2})".format(selector, animate, offset)) - - def set_route(self, *args): - self.execute_script('frappe.set_route({0})'\ - .format(', '.join(['"{0}"'.format(r) for r in args]))) - - self.wait_for(xpath='//div[@data-page-route="{0}"]'.format('/'.join(args)), timeout=4) - - def click(self, css_selector, xpath=None, timeout=20, animate=0, offset=0): - element = self.wait_till_clickable(css_selector, xpath, timeout) - self.scroll_to(css_selector, animate, offset) - time.sleep(0.5) - element.click() - return element - - def click_primary_action(self): - selector = ".page-actions .primary-action" - #self.scroll_to(selector) - self.wait_till_clickable(selector).click() - self.wait_for_ajax() - - def click_secondary_action(self): - selector = ".page-actions .btn-secondary" - #self.scroll_to(selector) - self.wait_till_clickable(selector).click() - self.wait_for_ajax() - - def click_modal_primary_action(self): - self.get_visible_modal().find_element_by_css_selector('.btn-primary').click() - - def get_visible_modal(self): - return self.get_visible_element('.modal-content') - - def get_visible_element(self, selector=None, xpath=None): - for elem in self.find(selector=selector, xpath=xpath): - if elem.is_displayed(): - return elem - - def wait_till_clickable(self, selector=None, xpath=None, timeout=20): - if self.cur_route: - selector = self.cur_route + " " + selector - - by = By.CSS_SELECTOR - if xpath: - by = By.XPATH - selector = xpath - - return self.get_wait(timeout).until(EC.element_to_be_clickable( - (by, selector))) - - - def execute_script(self, js): - self.driver.execute_script(js) - - def wait_for_ajax(self, freeze = False): - self.wait_for('body[data-ajax-state="complete"]', True) - if freeze: - self.wait_for_invisible(".freeze-message-container") - - -# def go_to_module(module_name, item=None): -# global cur_route -# -# # desktop -# find(".navbar-home", True)[0].click() -# cur_route = None -# wait("#page-desktop") -# -# page = "Module/" + module_name -# m = find('#page-desktop [data-link="{0}"] .app-icon'.format(page)) -# if not m: -# page = "List/" + module_name -# m = find('#page-desktop [data-link="{0}"] .app-icon'.format(page)) -# if not m: -# raise Exception("Module {0} not found".format(module_name)) -# -# m[0].click() -# wait_for_page(page) -# -# if item: -# elem = find('[data-label="{0}"]'.format(item))[0] -# elem.click() -# page = elem.get_attribute("data-route") -# wait_for_page(page) -# -# def new_doc(module, doctype): -# go_to_module(module, doctype) -# primary_action() -# wait_for_page("Form/" + doctype) -# -# def add_child(fieldname): -# find('[data-fieldname="{0}"] .grid-add-row'.format(fieldname))[0].click() -# wait('[data-fieldname="{0}"] .form-grid'.format(fieldname)) -# -# def done_add_child(fieldname): -# selector = '[data-fieldname="{0}"] .grid-row-open .btn-success'.format(fieldname) -# scroll_to(selector) -# wait_till_clickable(selector).click() -# -# def set_field(fieldname, value, fieldtype="input"): -# _driver.switch_to.window(_driver.current_window_handle) -# selector = '{0}[data-fieldname="{1}"]'.format(fieldtype, fieldname) -# set_input(selector, value, key=Keys.TAB) -# wait_for_ajax() -# -# def set_select(fieldname, value): -# select = Select(find('select[data-fieldname="{0}"]'.format(fieldname))[0]) -# select.select_by_value(value) -# wait_for_ajax() -# -# -# def wait_for_page(name): -# global cur_route -# cur_route = None -# route = '[data-page-route="{0}"]'.format(name) -# wait_for_ajax() -# elem = wait(route) -# wait_for_ajax() -# cur_route = route -# return elem -# -# -# def wait_till_visible(selector): -# if cur_route: -# selector = cur_route + " " + selector -# return get_wait().until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector))) -# -# -# def wait_for_state(state): -# return wait(cur_route + '[data-state="{0}"]'.format(state), True) -# -# diff --git a/requirements.txt b/requirements.txt index 84788c863e..84b77993b6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,6 @@ semantic_version rauth>=0.6.2 requests redis==2.10.6 -selenium babel==2.6.0 ipython html2text==2016.9.19