def test_bulk_create_updates_search_index(self): c1 = get_contract_recipe().prepare(labor_category='jr person') c2 = get_contract_recipe().prepare(labor_category='engineer') Contract.objects.bulk_create([c1, c2]) results = Contract.objects.multi_phrase_search('person').all() self.assertEqual([r.labor_category for r in results], ['jr person'])
def test_filter_by_schedule(self): get_contract_recipe().make(_quantity=3) resp = self.c.get(self.path, {'schedule': 'MOBIS'}) self.assertEqual(resp.status_code, 200) self.assertResultsEqual(resp.data['results'], [{'idv_piid': 'ABC1231', 'vendor_name': 'CompanyName1', 'labor_category': 'Business Analyst II', 'education_level': None, 'min_years_experience': 6, 'hourly_rate_year1': 21.0, 'current_price': 21.0, 'schedule': 'MOBIS', 'contractor_site': None, 'business_size': None}, {'idv_piid': 'ABC1233', 'vendor_name': 'CompanyName3', 'labor_category': 'Business Analyst II', 'education_level': None, 'min_years_experience': 8, 'hourly_rate_year1': 23.0, 'current_price': 23.0, 'schedule': 'MOBIS', 'contractor_site': None, 'business_size': None}])
def xtest_histogram_shows_min_max(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() histogram = driver.find_element_by_css_selector('.histogram') for metric in ('min', 'max', 'average'): node = histogram.find_element_by_class_name(metric) self.assertTrue(node.text.startswith(u'$'), "histogram '.%s' node does not start with '$': '%s'" % (metric, node.text))
def test_titles_are_correct(self): get_contract_recipe().make(_quantity=1, labor_category=seq("Architect")) driver = self.load_and_wait() self.assertTrue( driver.title.startswith('CALC'), 'Title mismatch, {} does not start with CALC'.format(driver.title))
def test_sortable_columns__non_default(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() for col in ['labor_category', 'education_level', 'min_years_experience']: self._test_column_is_sortable(driver, col)
def test_returns_empty_if_no_query(self): get_contract_recipe().make( labor_category='test' ) res = self.client.get(self.path) self.assertEqual(res.status_code, 200) self.assertEqual(res.json(), [])
def test_query_type__match_phrase(self): self.make_test_set() get_contract_recipe().make(_quantity=1, labor_category='Professional Legal Services I') resp = self.c.get(self.path, {'q': 'legal services', 'query_type': 'match_phrase'}) self.assertEqual(resp.status_code, 200) self.assertResultsEqual(resp.data['results'], [{'idv_piid': 'ABC123', 'vendor_name': 'ACME Corp.', 'labor_category': 'Legal Services', 'education_level': None, 'min_years_experience': 10, 'hourly_rate_year1': 18.0, 'current_price': 18.0, 'schedule': None, 'contractor_site': None, 'business_size': None}, {'idv_piid': 'ABC1231', 'vendor_name': 'CompanyName1', 'labor_category': 'Professional Legal Services I', 'education_level': None, 'min_years_experience': 6, 'hourly_rate_year1': 21.0, 'current_price': 21.0, 'schedule': 'MOBIS', 'contractor_site': None, 'business_size': None}])
def test_sort_by_education_level__asc(self): # deliberately placing education level cycle out of order so that proper ordering cannot be # a side-effect of ordering by idv_piid or another serially-generated field get_contract_recipe().make(_quantity=5, education_level=cycle(['MA', 'HS', 'BA', 'AA', 'PHD'])) resp = self.c.get(self.path, {'sort': '-education_level'}) self.assertEqual(resp.status_code, 200) self.assertResultsEqual(resp.data['results'], [ { 'idv_piid': 'ABC1235', 'vendor_name': 'CompanyName5', 'labor_category': 'Business Analyst II', 'education_level': 'Ph.D.', 'min_years_experience': 10, 'hourly_rate_year1': 25.0, 'current_price': 25.0, 'schedule': 'MOBIS', 'contractor_site': None, 'business_size': None}, { 'idv_piid': 'ABC1231', 'vendor_name': 'CompanyName1', 'labor_category': 'Business Analyst II', 'education_level': 'Masters', 'min_years_experience': 6, 'hourly_rate_year1': 21.0, 'current_price': 21.0, 'schedule': 'MOBIS', 'contractor_site': None, 'business_size': None}, { 'idv_piid': 'ABC1233', 'vendor_name': 'CompanyName3', 'labor_category': 'Business Analyst II', 'education_level': 'Bachelors', 'min_years_experience': 8, 'hourly_rate_year1': 23.0, 'current_price': 23.0, 'schedule': 'MOBIS', 'contractor_site': None, 'business_size': None}, { 'idv_piid': 'ABC1234', 'vendor_name': 'CompanyName4', 'labor_category': 'Business Analyst II', 'education_level': 'Associates', 'min_years_experience': 9, 'hourly_rate_year1': 24.0, 'current_price': 24.0, 'schedule': 'PES', 'contractor_site': None, 'business_size': None}, { 'idv_piid': 'ABC1232', 'vendor_name': 'CompanyName2', 'labor_category': 'Business Analyst II', 'education_level': 'High School', 'min_years_experience': 7, 'hourly_rate_year1': 22.0, 'current_price': 22.00, 'schedule': 'PES', 'contractor_site': None, 'business_size': None}, ])
def test_contract_link(self): get_contract_recipe().make(_quantity=1, idv_piid='GS-23F-0062P') driver = self.load_and_wait() form = self.get_form() contract_link = driver.find_element_by_xpath('//*[@id="results-table"]/tbody/tr[1]/td[5]/a') redirect_url = 'https://www.gsaadvantage.gov/ref_text/GS23F0062P/GS23F0062P_online.htm' self.assertEqual(contract_link.get_attribute('href'), redirect_url)
def xtest_histogram_shows_intevals(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() ticks = driver.find_elements_by_css_selector( '.histogram .x.axis .tick') # XXX there should be 10 bins, but 11 labels (one for each bin edge) self.assertEqual(len(ticks), 11, "Found wrong number of x-axis ticks: %d" % len(ticks))
def test_histogram_shows_tooltips(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() bars = driver.find_elements_by_css_selector('.histogram .bar') # TODO: check for "real" tooltips? for i, bar in enumerate(bars): title = bar.find_element_by_css_selector('title') self.assertIsNotNone(title.text, "Histogram bar #%d has no text" % i)
def test_titles_are_correct(self): get_contract_recipe().make(_quantity=1, labor_category=seq("Architect")) driver = self.load_and_wait() self.assertTrue( driver.title.startswith('CALC'), 'Title mismatch, {} does not start with CALC'.format(driver.title) )
def test_histogram_is_shown(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() rect_count = len( driver.find_elements_by_css_selector('.histogram rect')) self.assertTrue( rect_count > 0, "No histogram rectangles found (selector: '.histogram rect')")
def test_there_is_no_business_size_column(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("Large Biz"), business_size='o') driver = self.load() form = self.get_form() col_headers = get_column_headers(driver) for head in col_headers: self.assertFalse(has_matching_class(head, 'column-business[_-]size'))
def xtest_no_filter_shows_all_sizes_of_business(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("Large Biz"), business_size='o') get_contract_recipe().make(_quantity=5, vendor_name=seq("Small Biz"), business_size='s') driver = self.load_and_wait() self.assert_results_count(driver, 10) self.assertIsNotNone(re.search(r'Small Biz\d+', driver.page_source)) self.assertIsNotNone(re.search(r'Large Biz\d+', driver.page_source))
def test_no_filter_shows_all_sizes_of_business(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("Large Biz"), business_size='o') get_contract_recipe().make(_quantity=5, vendor_name=seq("Small Biz"), business_size='s') driver = self.load_and_wait() self.assert_results_count(driver, 10) self.assertIsNotNone(re.search(r'Small Biz\d+', driver.page_source)) self.assertIsNotNone(re.search(r'Large Biz\d+', driver.page_source))
def test_histogram_is_shown(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() rect_count = len( driver.find_elements_by_css_selector('.histogram rect')) self.assertTrue( rect_count > 0, "No histogram rectangles found (selector: '.histogram rect')" )
def test_filter_by_education_single(self): get_contract_recipe().make(_quantity=5, education_level=cycle(['MA', 'HS', 'BA', 'AA', 'PHD'])) resp = self.c.get(self.path, {'education': 'AA', 'sort': 'education_level'}) self.assertEqual(resp.status_code, 200) self.assertResultsEqual(resp.data['results'], [ { 'idv_piid': 'ABC1234', 'education_level': 'Associates' } ], True)
def xtest_form_submit_loading(self): get_contract_recipe().make(_quantity=1, labor_category=seq("Architect")) self.load() self.search_for('Architect') form = self.submit_form() # print(self.driver.execute_script('document.querySelector("#search").className')) self.assertTrue(has_class(form, 'loading'), "Form doesn't have 'loading' class") self.wait_for(self.data_is_loaded) self.assertTrue(has_class(form, 'loaded'), "Form doesn't have 'loaded' class") self.assertFalse(has_class(form, 'loading'), "Form shouldn't have 'loading' class after loading")
def test_query_type_matches_words(self): get_contract_recipe().make(_quantity=3, labor_category=cycle(['Systems Engineer', 'Software Engineer', 'Consultant'])) driver = self.load() form = self.get_form() self.search_for('engineer') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector('table.results tbody .column-labor_category') self.assertEqual(len(cells), 2, 'wrong cell count: %d (expected 2)' % len(cells)) for cell in cells: self.assertTrue('Engineer' in cell.text, 'found cell without "Engineer": "%s"' % cell.text)
def test_query_type_matches_phrase(self): get_contract_recipe().make(_quantity=3, labor_category=cycle(['Systems Engineer I', 'Software Engineer II', 'Consultant II'])) driver = self.load() form = self.get_form() self.search_for('software engineer') self.set_form_values(form, query_type='match_phrase') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector('table.results tbody .column-labor_category') self.assertEqual(len(cells), 1, 'wrong cell count: %d (expected 1)' % len(cells)) self.assertEqual(cells[0].text, 'Software Engineer II', 'bad cell text: "%s"' % cells[0].text)
def test_price_column_is_sortable_and_is_the_default_sort(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() col_header = find_column_header(driver, 'current_price') # current_price should be sorted ascending by default self.assertTrue(has_class(col_header, 'sorted'), "current_price is not the default sort") self.assertTrue(has_class(col_header, 'sortable'), "current_price column is not sortable") self.assertFalse(has_class(col_header, 'descending'), "current_price column is descending by default") col_header.click() self.assertTrue(has_class(col_header, 'sorted'), "current_price is still sorted after clicking")
def xtest_filter_order_is_correct(self): get_contract_recipe().make(_quantity=1, labor_category=seq("Architect")) driver = self.load() form = self.get_form() inputs = form.find_elements_by_css_selector("input:not([type='hidden'])") # the last visible form inputs should be the price filters self.assertEqual(inputs[-2].get_attribute('name'), 'price__gte') self.assertEqual(inputs[-1].get_attribute('name'), 'price__lte')
def test_search_input(self): get_contract_recipe().make(_quantity=9, labor_category=cycle(["Engineer", "Architect", "Writer"])) driver = self.load() self.search_for('Engineer') self.submit_form() self.assertTrue('q=Engineer' in driver.current_url, 'Missing "q=Engineer" in query string') self.wait_for(self.data_is_loaded) self.assert_results_count(driver, 3) labor_cell = driver.find_element_by_css_selector('tbody tr .column-labor_category') self.assertTrue('Engineer' in labor_cell.text, 'Labor category cell text mismatch')
def xtest_filter_year_out(self): get_contract_recipe().make(_quantity=1, second_year_price=23.45) driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'contract-year', "2") self.submit_form_and_wait() self.assert_results_count(driver, 1) rate = driver.find_element_by_xpath('//*[@id="results-table"]/tbody/tr[1]/td[4]') self.assertEqual(rate.text, '$23.45')
def test_query_type_matches_words(self): get_contract_recipe().make(_quantity=3, labor_category=cycle(['Systems Engineer', 'Software Engineer', 'Consultant'])) driver = self.load() self.wait_for(self.data_is_loaded) form = self.get_form() self.search_for('engineer') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector('table.results tbody .column-labor_category') self.assertEqual(len(cells), 2, 'wrong cell count: %d (expected 2)' % len(cells)) for cell in cells: self.assertTrue('Engineer' in cell.text, 'found cell without "Engineer": "%s"' % cell.text)
def xtest_search_input(self): get_contract_recipe().make(_quantity=9, labor_category=cycle(["Engineer", "Architect", "Writer"])) driver = self.load() self.search_for('Engineer') self.submit_form() self.assertTrue('q=Engineer' in driver.current_url, 'Missing "q=Engineer" in query string') self.wait_for(self.data_is_loaded) self.assert_results_count(driver, 3) labor_cell = driver.find_element_by_css_selector('tbody tr .column-labor_category') self.assertTrue('Engineer' in labor_cell.text, 'Labor category cell text mismatch')
def test_query_type_matches_phrase(self): get_contract_recipe().make(_quantity=3, labor_category=cycle(['Systems Engineer I', 'Software Engineer II', 'Consultant II'])) driver = self.load() self.wait_for(self.data_is_loaded) form = self.get_form() self.search_for('software engineer') self.set_form_values(form, query_type='match_phrase') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector('table.results tbody .column-labor_category') self.assertEqual(len(cells), 1, 'wrong cell count: %d (expected 1)' % len(cells)) self.assertEqual(cells[0].text, 'Software Engineer II', 'bad cell text: "%s"' % cells[0].text)
def test_filter_year_out(self): get_contract_recipe().make(_quantity=1, second_year_price=23.45) driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'contract-year', "2") self.submit_form_and_wait() self.assert_results_count(driver, 1) rate = driver.find_element_by_xpath('//*[@id="results-table"]/tbody/tr[1]/td[4]') self.assertEqual(rate.text, '$23.45')
def test_query_type_matches_exact(self): get_contract_recipe().make(_quantity=3, labor_category=cycle(['Software Engineer I', 'Software Engineer', 'Senior Software Engineer'])) driver = self.load() form = self.get_form() self.search_for('software engineer') self.set_form_values(form, query_type='match_exact') # self.assertEqual(driver.execute_script('document.querySelector("input[value=\'match_exact\']").checked'), True, 'match_exact not checked!') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector('table.results tbody .column-labor_category') self.assertEqual(len(cells), 1, 'wrong cell count: %d (expected 1)' % len(cells)) self.assertEqual(cells[0].text, 'Software Engineer', 'bad cell text: "%s"' % cells[0].text)
def test_query_type_matches_exact(self): get_contract_recipe().make(_quantity=3, labor_category=cycle(['Software Engineer I', 'Software Engineer', 'Senior Software Engineer'])) driver = self.load() self.wait_for(self.data_is_loaded) form = self.get_form() self.search_for('software engineer') self.set_form_values(form, query_type='match_exact') # self.assertEqual(driver.execute_script('document.querySelector("input[value=\'match_exact\']").checked'), True, 'match_exact not checked!') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector('table.results tbody .column-labor_category') self.assertEqual(len(cells), 1, 'wrong cell count: %d (expected 1)' % len(cells)) self.assertEqual(cells[0].text, 'Software Engineer', 'bad cell text: "%s"' % cells[0].text)
def test_retrieving_multiple_pages_works(self): get_contract_recipe().make(_quantity=5) stdout = io.StringIO() call_command( 'load_api_data', url=f"{self.live_server_url}/api/rates/", dry_run=True, stdout=stdout ) self.assertRegex( stdout.getvalue(), 'Processed 5 rates in dry run mode over 3 pages' )
def test_query_type_matches_phrase(self): get_contract_recipe().make( _quantity=3, labor_category=cycle(["Systems Engineer I", "Software Engineer II", "Consultant II"]) ) driver = self.load() self.wait_for(self.data_is_loaded) form = self.get_form() self.search_for("software engineer") self.set_form_values(form, query_type="match_phrase") self.submit_form_and_wait() cells = driver.find_elements_by_css_selector("table.results tbody .column-labor_category") self.assertEqual(len(cells), 1, "wrong cell count: %d (expected 1)" % len(cells)) self.assertEqual(cells[0].text, "Software Engineer II", 'bad cell text: "%s"' % cells[0].text)
def xtest_filter_to_only_large_businesses(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("Large Biz"), business_size='o') get_contract_recipe().make(_quantity=5, vendor_name=seq("Small Biz"), business_size='s') driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'business_size', 'o') self.submit_form_and_wait() self.assert_results_count(driver, 5) self.assertIsNone(re.search(r'Small Biz\d+', driver.page_source)) self.assertIsNotNone(re.search(r'Large Biz\d+', driver.page_source))
def xtest_filter_schedules(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("MOBIS"), schedule='MOBIS') get_contract_recipe().make(_quantity=5, vendor_name=seq("AIMS"), schedule='AIMS') driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'schedule', 'MOBIS') self.submit_form_and_wait() self.assert_results_count(driver, 5) self.assertIsNone(re.search(r'AIMS\d+', driver.page_source)) self.assertIsNotNone(re.search(r'MOBIS\d+', driver.page_source))
def test_filter_to_only_large_businesses(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("Large Biz"), business_size='o') get_contract_recipe().make(_quantity=5, vendor_name=seq("Small Biz"), business_size='s') driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'business_size', 'o') self.submit_form_and_wait() self.assert_results_count(driver, 5) self.assertIsNone(re.search(r'Small Biz\d+', driver.page_source)) self.assertIsNotNone(re.search(r'Large Biz\d+', driver.page_source))
def test_filter_schedules(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("MOBIS"), schedule='MOBIS') get_contract_recipe().make(_quantity=5, vendor_name=seq("AIMS"), schedule='AIMS') driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'schedule', 'MOBIS') self.submit_form_and_wait() self.assert_results_count(driver, 5) self.assertIsNone(re.search(r'AIMS\d+', driver.page_source)) self.assertIsNotNone(re.search(r'MOBIS\d+', driver.page_source))
def test_one_column_is_sortable_at_a_time(self): get_contract_recipe().make(_quantity=5) driver = self.load_and_wait() header1 = find_column_header(driver, 'education_level') header2 = find_column_header(driver, 'labor_category') header1.click() self.assertTrue(has_class(header1, 'sorted'), "column 1 is not sorted") self.assertFalse(has_class(header2, 'sorted'), "column 2 is still sorted (but should not be)") header2.click() self.assertTrue(has_class(header2, 'sorted'), "column 2 is not sorted") self.assertFalse(has_class(header1, 'sorted'), "column 1 is still sorted (but should not be)")
def test_filter_experience_range(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("4 years of experience"), min_years_experience=4) get_contract_recipe().make(_quantity=5, vendor_name=seq("5 years of experience"), min_years_experience=5) driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, 'experience_range', '5,10') self.submit_form_and_wait() self.assert_results_count(driver, 5) self.assertIsNone(re.search(r'4 years of experience\d+', driver.page_source)) self.assertIsNotNone(re.search(r'5 years of experience\d+', driver.page_source))
def xtest_filter_to_only_small_businesses(self): get_contract_recipe().make(_quantity=5, vendor_name=seq("Large Biz"), business_size="o") get_contract_recipe().make(_quantity=5, vendor_name=seq("Small Biz"), business_size="s") driver = self.load_and_wait() form = self.get_form() self.set_form_value(form, "business_size", "s") self.submit_form_and_wait() self.assert_results_count(driver, 5) self.assertIsNone(re.search(r"Large Biz\d+", driver.page_source)) self.assertIsNotNone(re.search(r"Small Biz\d+", driver.page_source))
def xtest_form_submit_loading(self): get_contract_recipe().make(_quantity=1, labor_category=seq("Architect")) self.load() self.search_for('Architect') form = self.submit_form() self.assertTrue(has_class(form, 'loading'), "Form doesn't have 'loading' class") self.wait_for(self.data_is_loaded) self.assertTrue(has_class(form, 'loaded'), "Form doesn't have 'loaded' class") self.assertFalse(has_class(form, 'loading'), "Form shouldn't have 'loading' class after loading")
def test_stops_retrieving_at_end_page(self): get_contract_recipe().make(_quantity=5) stdout = io.StringIO() call_command( 'load_api_data', url=f"{self.live_server_url}/api/rates/", dry_run=True, end_page=1, stdout=stdout ) self.assertRegex( stdout.getvalue(), 'Processed 2 rates in dry run mode over 1 pages' )
def xtest_hide_schedule_column(self): get_contract_recipe().make(_quantity=5) driver = self.load() col_header = find_column_header(driver, 'schedule') # hide column col_header.find_element_by_css_selector('.toggle-collapse').click() self.assertTrue(has_class(col_header, 'collapsed')) # re-show column col_header.find_element_by_css_selector('.toggle-collapse').click() self.assertFalse(has_class(col_header, 'collapsed'))
def test_hide_schedule_column(self): get_contract_recipe().make(_quantity=5) driver = self.load() col_header = find_column_header(driver, 'schedule') # hide column col_header.find_element_by_css_selector('.toggle-collapse').click() self.assertTrue(has_class(col_header, 'collapsed')) # re-show column col_header.find_element_by_css_selector('.toggle-collapse').click() self.assertFalse(has_class(col_header, 'collapsed'))
def test_query_type_matches_exact(self): get_contract_recipe().make(_quantity=3, labor_category=cycle( ['Software Engineer I', 'Software Engineer', 'Senior Software Engineer'])) driver = self.load() self.wait_for(self.data_is_loaded) self.search_for_query_type('software engineer', 'match_exact') self.submit_form_and_wait() cells = driver.find_elements_by_css_selector( 'table.results tbody .column-labor_category') self.assertEqual( len(cells), 1, 'wrong cell count: %d (expected 1)' % len(cells)) self.assertEqual(cells[0].text, 'Software Engineer', 'bad cell text: "%s"' % cells[0].text)