def test_query_seqs_display(self): """ Tests the query sequences display page """ # User visits home page and submits a protein alignment self.client.get(self.url) csrftoken = self.client.cookies["csrftoken"] alignment_string = file_to_string("spa_protein_alignment.fasta") self.client.headers.update({"referer": self.url}) r = self.client.post( self.url, data={"csrfmiddlewaretoken": csrftoken, "seq_type": "Protein", "align_input": alignment_string} ) display = html.parse(StringIO(r.text)).getroot() title = display.cssselect('title[id="head-title"]') sequence_lines = display.cssselect('p[class="query_seq_display"]') sequence_meta = display.find_class("query_seq_meta") render_form = display.cssselect('form[id="render"]') # She is redirected to a page showing the submitted sequences from her alignment and a simple consensus sequence self.assertEqual(r.status_code, 200, r.status_code) self.assertEqual( "%s/query-sequences" % self.url, "/".join(r.url.split("/")[:-2]), "/".join(r.url.split("/")[:-2]) ) self.assertEqual("Formalign.eu Sequence Display", title[0].text_content(), title[0].text_content()) self.assertIsNotNone(sequence_lines, "sequences are empty") for l in sequence_lines: self.assertTrue(len(l.text_content()) <= 80, l.text_content()) seqs = file_to_string("spa_protein_alignment_display.txt").splitlines() for i, a in enumerate(seqs): self.assertEqual( a, sequence_lines[i].text_content(), "%s: %s" % (format(i), sequence_lines[i].text_content()) ) seqs_meta = file_to_string("spa_protein_alignment_display_meta.txt").splitlines() for i, a in enumerate(seqs_meta): self.assertEqual(a, sequence_meta[i].text_content(), sequence_meta[i].text_content()) # She is happy with the result, sees a "Render" button and clicks it. self.assertEqual("get", render_form[0].attrib.get("method"), render_form[0].attrib.get("method")) self.assertEqual( "align-display", render_form[0].attrib.get("action").split("/")[1], render_form[0].attrib.get("action").split("/")[1], ) slug_pattern = re.compile("^([a-zA-Z]|\d){16}$") self.assertTrue( re.match(slug_pattern, render_form[0].attrib.get("action").split("/")[-2]), render_form[0].attrib.get("action").split("/")[-2], ) r = self.client.get(self.url + render_form[0].attrib.get("action")) # She is redirected to the render page self.assertEqual(r.status_code, 200, r.status_code) align = html.parse(StringIO(r.text)).getroot() title = align.cssselect('title[id="head-title"]') self.assertEqual("Formalign.eu Alignment Display", title[0].text_content(), title[0].text_content()) self.assertEqual( "%s/align-display" % self.url, "/".join(r.url.split("/")[:-2]), "/".join(r.url.split("/")[:-2]) )
def setUp(self): """ Creates an alignment from ser_thr_kin_short in the db """ align_input = io.StringIO(file_to_string("ser_thr_kin_short.fasta")) data = parse_fasta_alignment(align_input) for d in data: d.seq.alphabet = Gapped(ExtendedIUPACProtein()) self.alignment = data align_input_a = io.StringIO(file_to_string("protein_annotate_test.fasta")) data_a = parse_fasta_alignment(align_input_a) for d in data_a: d.seq.alphabet = Gapped(ExtendedIUPACProtein()) self.alignment_a = data_a
def setUp(self): name = "A. tha. SPA family protein alignment" align_input = io.StringIO(file_to_string("spa_protein_alignment.fasta")) data = parse_fasta_alignment(align_input) for d in data: d.seq.alphabet = Gapped(ExtendedIUPACProtein()) align = Alignment.objects.create_alignment(name, data) self.response_prot = self.client.get("/query-sequences/" + str(align.slug) + "/") name = "A. tha. SPA family DNA alignment" align_input = io.StringIO(file_to_string("spa_cds_alignment.fasta")) data = parse_fasta_alignment(align_input) for d in data: d.seq.alphabet = Gapped(ExtendedIUPACDNA()) align = Alignment.objects.create_alignment(name, data) self.response_dna = self.client.get("/query-sequences/" + str(align.slug) + "/")
def test_form_validation_returns_correct_seqrecord_alphabet(self): """ Tests that seqrecords get correct alphabet according to user input of seq_type :return: """ input_seqs = file_to_string('protein.fasta') form = QueryForm(data={'align_input': input_seqs, 'seq_type': 'Protein'}) self.assertTrue(form.is_valid()) for f in form.cleaned_data['align_input']: self.assertEqual(str(f.seq.alphabet), "Gapped(ExtendedIUPACProtein(), '-')", Gapped(ExtendedIUPACProtein()).letters) input_seqs = file_to_string('DNA.fasta') form = QueryForm(data={'align_input': input_seqs, 'seq_type': 'DNA'}) self.assertTrue(form.is_valid()) for f in form.cleaned_data['align_input']: self.assertEqual(str(f.seq.alphabet), "Gapped(ExtendedIUPACDNA(), '-')", Gapped(ExtendedIUPACDNA()).letters)
def test_alignment_display_speeds(self): """ Tests alignment display page """ # User visits home page, submits a protein alignment and renders it files = [ 'spa_protein_alignment.fasta', 'spa1_protein_alignment.fasta', 'ser_thr_kinase_family.fasta' ] for f in files: q_display = [] a_display = [] for i in range(3): self.client = requests.Session() self.client.get(self.live_server_url) csrftoken = self.client.cookies['csrftoken'] alignment_string = file_to_string(f) start = time.time() r = self.client.post(self.live_server_url, data={'csrfmiddlewaretoken': csrftoken, 'seq_type': 'Protein', 'align_input': alignment_string}) roundtrip1 = time.time() - start q_display.append(roundtrip1) render_form = html.parse(StringIO(r.text)).getroot().cssselect('form[id="render"]') start = time.time() r = self.client.get(self.live_server_url + render_form[0].attrib.get('action')) roundtrip2 = time.time() - start a_display.append(roundtrip2) self.client.close() self.assertTrue(mean(q_display) <= 2, 'query sequences display of %s took: %s' % (f, mean(q_display))) self.assertTrue(mean(a_display) <= 2, 'alignment display of %s took: %s' % (f, mean(a_display)))
def test_align_display_page_displays_correct_consensus(self): """ Tests that align_display displays the correct consensus sequence """ expected_seqs = file_to_string("spa_protein_alignment.fasta") align_expected = io.StringIO(expected_seqs) alignment = parse_fasta_alignment(align_expected) alignment = consensus_add(alignment) # get displayed sequences with self.assertHTML(self.response, "tr") as elems: seq_disp = [] for els in elems: seq_disp_line = [] for e in els.findall("td")[:-1]: if e.attrib["class"] in ["residue S0", "residue S1"]: seq_disp_line.append(e.text) if seq_disp_line: seq_disp.append(seq_disp_line) # recompose sequences cat_re_seq = [] for j in range(len(alignment) - 1, len(seq_disp), len(alignment)): re_seq = [seq_disp[j] for j in range(len(alignment) - 1, len(seq_disp), len(alignment))] cat_re_seq = [] for r in re_seq: cat_re_seq.extend(r) # check consensus cons_li = list(alignment[-1].seq) self.assertEqual(cons_li, cat_re_seq, cat_re_seq)
def test_align_display_page_displays_correct_protein_alignment_sequence(self): """ Tests that align_display displays an alignment with correct sequences """ expected_seqs = file_to_string("spa_protein_alignment.fasta") align_expected = io.StringIO(expected_seqs) alignment = parse_fasta_alignment(align_expected) # get displayed sequences with self.assertHTML(self.response, "tr") as elems: seq_disp = [] for els in elems: seq_disp_line = [] for e in els.findall("td")[:-1]: if e.attrib["class"] in ["residue S0", "residue S1"]: seq_disp_line.append(e.text) if seq_disp_line: seq_disp.append(seq_disp_line) # recompose sequences re_seqs = [] cat_re_seq = [] for i in range(0, len(alignment) + 1): for j in range(i, len(seq_disp), len(alignment) + 1): re_seq = [seq_disp[j] for j in range(i, len(seq_disp), len(alignment) + 1)] cat_re_seq = [] for r in re_seq: cat_re_seq.extend(r) re_seqs.append(cat_re_seq) # check sequences against original alignment for i, al in enumerate(alignment): al_li = list(al.seq) self.assertEqual(al_li, re_seqs[i], re_seqs[i])
def test_redirect_to_seqdisplay_on_post(self): """ Tests that valid POST request on index page redirects to /query-sequences/ :return: """ input_seqs = file_to_string("spa_protein_alignment.fasta") response = self.client.post("/", {"align_input": input_seqs, "seq_type": "Protein"}) self.assertTrue("/query-sequences/" in response.url)
def setUp(self): self.name = 'A. tha. SPA family alignment' align_input = io.StringIO(file_to_string('spa_protein_alignment.fasta')) self.data = parse_fasta_alignment(align_input) alphabet = Gapped(ExtendedIUPACProtein()) for a in self.data: a.seq.alphabet = alphabet self.data._alphabet = alphabet
def test_display_page_uses_display_seq_template(self): """ Tests that seq_display view returns a 200 response on a POST request and uses the correct template :return: """ input_seqs = file_to_string("protein.fasta") response = self.client.post("/", {"align_input": input_seqs, "seq_type": "DNA"}) self.assertEqual(response.status_code, 200)
def setUp(self): name = 'A. tha. SPA family protein alignment' align_input = io.StringIO(file_to_string('spa_protein_alignment.fasta')) data = parse_fasta_alignment(align_input) for d in data: d.seq.alphabet = Gapped(ExtendedIUPACProtein()) align = Alignment.objects.create_alignment(name, data) self.slug = align.slug
def test_alignment_is_saved_on_post(self): """ Tests that alignment is saved on valid POST request to index :return: """ input_seqs = file_to_string("spa_protein_alignment.fasta") response = self.client.post("/", {"align_input": input_seqs, "seq_type": "Protein"}) slug = re.match(r"^/query-sequences/(?P<align_id>([a-zA-Z]|\d){16})/", response.url).group("align_id") pk = Alignment.objects.get(slug=slug).pk alignment = Alignment.objects.get_alignment(pk) self.assertEqual([seq.id for seq in alignment], ["NP_175717", "NP_683567", "NP_182157", "NP_192849"])
def test_parse_fasta_alignment_returns_expected_object(self): """ tests that parse_fasta_alignment returns the expected object """ align = io.StringIO(file_to_string("ser_thr_kin_short.fasta")) parsed = parse_fasta_alignment(align) self.assertEqual( ["DMD401_1-640", "CER09D1_11-435", "EGFR", "DMDPR2_1-384"], [p.description for p in parsed], [p.description for p in parsed], )
def test_parse_fasta_alignment(self): """ Tests that the parse_fasta function returns expected values with a valid fasta alignment :return: """ input_seqs = file_to_string("protein.fasta") parsed = parse_fasta_alignment(io.StringIO(input_seqs)) self.assertEqual(parsed[0].description, "sequence1") self.assertEqual(parsed[0].seq, "MKERBGWAQ--QGKKPWRF--EEW") self.assertEqual(parsed[1].description, "sequence2") self.assertEqual(parsed[1].seq, "MKERBGWA-SYQGKKPWRFAQ-EW")
def setUp(self): """ Creates a response from a GET request to /align-display/ with an alignment pk :param input_file: file containing alignment :return: response """ name = "SPA1 protein alignment" align_input = io.StringIO(file_to_string("spa1_protein_alignment.fasta")) data = parse_fasta_alignment(align_input) for d in data: d.seq.alphabet = Gapped(ExtendedIUPACProtein()) self.align = Alignment.objects.create_alignment(name, data)
def response_for_invalid_post_request(self, input_file="", seq_type="Protein"): """ Creates a response from a POST request to /query-sequences/ with an invalid alignment :param input_file: file containing invalid alignment :return: response """ if input_file: input_seqs = file_to_string(input_file) else: input_seqs = "" response = self.client.post("/", {"align_input": input_seqs, "seq_type": seq_type}) return response
def test_display_page_uses_display_seq_template_on_GET(self): """ Tests that seq_display view returns a 200 response on a GET request and uses the correct template :return: """ name = "A. tha. SPA family alignment" align_input = io.StringIO(file_to_string("spa_protein_alignment.fasta")) data = parse_fasta_alignment(align_input) for d in data: d.seq.alphabet = Gapped(ExtendedIUPACProtein()) save = Alignment.objects.create_alignment(name, data) response = self.client.get("/query-sequences/" + str(save.slug) + "/") self.assertEqual(response.status_code, 200)
def setUp(self): seq_input = io.StringIO(file_to_string('spa_protein_alignment.fasta')) data = SeqIO.parse(seq_input, 'fasta') self.seqs = [d.upper() for d in data] for s in self.seqs: s.seq.alphabet = ExtendedIUPACProtein() self.seq = Seqrecord.objects.create( seq=str(self.seqs[0].seq), alphabet=str(self.seqs[0].seq.alphabet), seq_id=str(self.seqs[0].id), name=str(self.seqs[0].name), description=self.seqs[0].description, )
def test_display_page_displays_consensus(self): """ Tests that seq_display displays the consensus sequence on a valid POST request :return: """ response = self.response_prot with self.assertHTML(response, 'h3[class="query_seq_meta bg-color-body"]') as elems: self.assertEqual(elems[-1].text, "consensus 70%:", "consensus meta: " + format(elems[0].text)) cons_seq = file_to_string("consensus.txt") with self.assertHTML(response, 'div[class="query_seq bg-color-body"]') as elems: self.assertEqual( elems[-1].findall("p")[0].text, cons_seq[:80], "consensus seq: " + elems[-1].findall("p")[0].text ) self.assertNotIn(" ", elems[-1].findall("p")[0].text) self.assertNotIn("\n", elems[-1].findall("p")[0].text)
def validation(self, error_text, input_file='', seq_type='Protein'): """ Performs validation test for invalid forms, takes a user alignment input, asserts form.is_valid as false and checks the error :param: :return: """ if input_file: input_seqs = file_to_string(input_file) else: input_seqs = '' form = QueryForm(data={'align_input': input_seqs, 'seq_type': seq_type}) self.assertFalse(form.is_valid()) self.assertEqual( form.errors['align_input'], [error_text], format(form.errors['align_input']) )
def test_align_display_page_displays_sequences_in_the_correct_order(self): """ Tests that align_display displays the sequences in the correct order """ expected_seqs = file_to_string("spa_protein_alignment.fasta") align_expected = io.StringIO(expected_seqs) alignment = parse_fasta_alignment(align_expected) ids = [al.id for al in alignment] ids.append("consensus 70%") with self.assertHTML(self.response, "tr") as elems: ids_disp = [] for els in elems: for e in els.findall("td")[:-1]: if e.attrib["class"] == "seq_id": ids_disp.append(e.text) # blocks of sequence IDs bl = [ids_disp[i : i + len(ids)] for i in range(0, len(ids_disp), len(ids))] for b in bl: for i in range(len(ids)): self.assertEqual(ids[i], b[i], b[i])
def alignment_validation(self, seqs): # She visits the Formalign.eu site r = self.client.get(self.url) csrftoken = self.client.cookies['csrftoken'] index = html.parse(StringIO(r.text)).getroot() title = index.cssselect('title[id="head-title"]') brand = index.cssselect('a[class="navbar-brand"]') # page displays no error message self.assertEqual(r.status_code, 200, r.status_code) # User sees she's on the right page because she can see the name of the site in the title and the brand. self.assertEqual('Formalign.eu Home', title[0].text_content(), title[0].text_content()) self.assertEqual(self.url + '/', r.url, r.url) self.assertEqual('Formalign.eu', brand[0].text_content(), brand[0].text_content()) for t in ['protein', 'DNA']: for s in seqs: # she submits the invalid alignment alignment_string = file_to_string('%s%s.fasta' % (t, s['seq'])) if s['seq'] else None self.client.headers.update({'referer': self.url}) r = self.client.post(self.url, data={'csrfmiddlewaretoken': csrftoken, 'seq_type': 'Protein', 'align_input': alignment_string}) index = html.parse(StringIO(r.text)).getroot() title = index.cssselect('title[id="head-title"]') brand = index.cssselect('a[class="navbar-brand"]') error_text = index.cssselect('ul[class="errorlist"]')[0].cssselect('li')[0].text_content() # response contains no error code self.assertEqual(r.status_code, 200, r.status_code) # user is redirected to the index page self.assertEqual('Formalign.eu Home', title[0].text_content(), title[0].text_content()) self.assertEqual(self.url + '/', r.url, r.url) self.assertEqual('Formalign.eu', brand[0].text_content(), brand[0].text_content()) # error text is displayed on index page self.assertEqual(s['error'], error_text, error_text)
def test_align_display_renders_correct_color_classes(self): """ Tests that align_display assigns the correct color classes (residue S0 or residue S1) to the residues """ expected_seqs = file_to_string("spa_protein_alignment.fasta") align_expected = io.StringIO(expected_seqs) alignment = parse_fasta_alignment(align_expected) alignment = consensus_add(alignment) alignment = annotate(alignment) # get displayed sequences with self.assertHTML(self.response, "tr") as elems: seq_disp = [] for els in elems: seq_disp_line = [] for e in els.findall("td")[:-1]: if e.attrib["class"] in ["residue S0", "residue S1"]: seq_disp_line.append(e.attrib["class"]) if seq_disp_line: seq_disp.append(seq_disp_line) # recompose sequences re_seqs = [] cat_re_seq = [] for i in range(0, len(alignment)): for j in range(i, len(seq_disp), len(alignment)): re_seq = [seq_disp[j] for j in range(i, len(seq_disp), len(alignment))] cat_re_seq = [] for r in re_seq: cat_re_seq.extend(r) re_seqs.append(cat_re_seq) # check color classes for i, al in enumerate(alignment): al_li = ["residue S%s" % a for a in al.letter_annotations["eq"]] self.assertEqual(al_li, re_seqs[i], re_seqs)
def invalid_format_sequence(self, file): seq_type_button_dict = {'DNA': 'input#id_seq_type_1', 'protein': 'input#id_seq_type_0'} test_seq = {'DNA': 'AGTCC-TAAGGTCGCCAATGGGCA', 'protein': 'MKERBGWAQ--QGKKPWRF--EEW'} # she visits the Formalign.eu site self.browser.get(self.url + '/') # She clicks the appropriate button and clears the input field seq_type_button = self.browser.find_element_by_css_selector(seq_type_button_dict[file['seq_type']]) seq_type_button.click() self.assertEqual( True, seq_type_button.is_selected(), 'button is selected for ' + file['align_format'] + ' ' + file['seq_type'] + ': ' + str(seq_type_button.is_selected()) ) alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_input.clear() # She pastes in an invalid fasta alignment alignment_string = file_to_string(file['invalid']) pyperclip.copy(alignment_string) alignment_input.send_keys(Keys.CONTROL, 'v') self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait) # Since her FASTA format is invalid she gets redirected to the submission form where she sees an # error message telling her that her alignment format is invalid self.assertEqual( 'Formalign.eu Home', self.browser.title, 'browser.title for ' + file['align_format'] + ' ' + file['seq_type'] + ': ' + self.browser.title ) error = self.browser.find_element_by_css_selector('.errorlist').find_element_by_tag_name('li') self.assertEqual( FORMAT_ERROR, error.text, 'error.text for ' + file['align_format'] + ' ' + file['seq_type'] + ': ' + error.text, ) # she corrects her alignment and submits an invalid clustal alignment alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_input.clear() alignment_string = file_to_string(file['valid']) pyperclip.copy(alignment_string) alignment_input.send_keys(Keys.CONTROL, 'v') self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait * 10) # She got it right this time and is redirected to a page showing the submitted sequences from her alignment self.assertEqual( 'Formalign.eu Sequence Display', self.browser.title, 'browser.title for ' + file['align_format'] + ' ' + file['seq_type'] + ': ' + self.browser.title) first_seq_info = self.browser.find_elements_by_css_selector('.query_seq_meta')[0] self.assertEqual( 'sequence1:', first_seq_info.text, 'seq id for ' + file['align_format'] + ' ' + file['seq_type'] + ': ' + first_seq_info.text ) first_seq_content = self.browser.find_elements_by_css_selector('.query_seq_display')[0] self.assertIsNotNone(first_seq_content) self.assertEqual( test_seq[file['seq_type']], first_seq_content.text, 'seq id for ' + file['align_format'] + ' ' + file['seq_type'] + ': ' + first_seq_content.text ) # She wonders whether she can use other formats and decides to navigate back to the home page home_button = self.browser.find_element_by_css_selector('.navbar-brand') home_button.click()
def alignment_validation(self, **kwargs): seq_type_button_dict = {'DNA': 'input#id_seq_type_1', 'protein': 'input#id_seq_type_0'} test_seq = {'DNA': 'AGTCC-TAAGGTCGCCAATGGGCA', 'protein': 'MKERBGWAQ--QGKKPWRF--EEW'} # User visits the formalign.eu site. self.browser.get(self.url + '/') # She clicks the DNA button seq_type_button = self.browser.find_element_by_css_selector(seq_type_button_dict[kwargs['seq_type']]) seq_type_button.click() # She is so excited that she inadvertently submits the empty input self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait) self.assertEqual('Formalign.eu Home', self.browser.title, self.browser.title) error = self.browser.find_element_by_css_selector('.errorlist').find_element_by_tag_name('li') self.assertEqual( EMPTY_ERROR, error.text ) # She decides to try it out so she pastes in an alignment and submits alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_string = file_to_string(kwargs['seq_type'] + '_invalid_fasta.fasta') alignment_input.send_keys(alignment_string) self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait) # unfortunately her FASTA format is invalid so she gets redirected to the submission form where she sees an # error message telling her that her FASTA format is invalid self.assertEqual(self.browser.title, 'Formalign.eu Home', self.browser.title) error = self.browser.find_element_by_css_selector('.errorlist').find_element_by_tag_name('li') self.assertEqual( FORMAT_ERROR, error.text ) # she corrects her alignment and resubmits alignment_string = file_to_string(kwargs['seq_type'] + '_invalid_characters.fasta') alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_input.clear() alignment_input.send_keys(alignment_string) self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait) # unfortunately now her sequences contain invalid characters so she gets redirected to the submission form # again where she sees an error message telling her that her sequences contain invalid characters self.assertEqual(self.browser.title, 'Formalign.eu Home', self.browser.title) error = self.browser.find_element_by_css_selector('.errorlist').find_element_by_tag_name('li') self.assertEqual( CHARACTER_ERROR + 'sequence1', error.text ) # she corrects her alignment again and resubmits alignment_string = file_to_string(kwargs['seq_type'] + '_too_few_sequences.fasta') alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_input.clear() alignment_input.send_keys(alignment_string) self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait) # unfortunately this time she accidentally erased one sequence and is left with only one sequence so she gets # redirected to the submission form again where she sees an error message telling her that her alignment is not # an alignment since it contains only one sequence self.assertEqual('Formalign.eu Home', self.browser.title, self.browser.title) error = self.browser.find_element_by_css_selector('.errorlist').find_element_by_tag_name('li') self.assertEqual( LESS_THAN_TWO_SEQS_ERROR, error.text, ) # she adds the missing sequence and resubmits alignment_string = file_to_string(kwargs['seq_type'] + '_invalid_alignment.fasta') alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_input.clear() alignment_input.send_keys(alignment_string) self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait) # it must be starting to be a bit late since she added some residues to her first sequence so it is longer than # the second now so she gets redirected to the submission form again where she sees an error message telling her # that her alignment is not an alignment since the sequences do not all have the same length self.assertEqual(self.browser.title, 'Formalign.eu Home', self.browser.title) error = self.browser.find_element_by_css_selector('.errorlist').find_element_by_tag_name('li') self.assertEqual( ALIGNMENT_ERROR, error.text, ) # She tries one final time and threatens to throw her laptop out of the window if she gets another # error message alignment_string = file_to_string(kwargs['seq_type'] + '.fasta') alignment_input = self.browser.find_element_by_css_selector('textarea#id_align_input') alignment_input.clear() alignment_input.send_keys(alignment_string) self.browser.find_element_by_id('submit-align').click() # Wait for Firefox time.sleep(self.wait * 5) # She got it right this time and is redirected to a page showing the submitted sequences from her alignment self.assertEqual(self.browser.title, 'Formalign.eu Sequence Display', self.browser.title) first_seq_info = self.browser.find_elements_by_css_selector('.query_seq_meta')[0] self.assertEqual( 'sequence1:', first_seq_info.text ) first_seq_content = self.browser.find_elements_by_css_selector('.query_seq_display')[0] self.assertIsNotNone(first_seq_content) self.assertEqual(first_seq_content.text, test_seq[kwargs['seq_type']])
def test_basic_user_experience(self): """ Tests basic user interaction with formalign.eu site """ # Lambda user is a biologist who has to make a nice figure containing a multiple alignment for a presentation. # She visits the formalign.eu site. self.browser.get(self.url + "/") # User sees she's on the right page because she can see the name of the site in the heading. self.assertEqual(self.browser.title, "Formalign.eu Home", self.browser.title) brand_element = self.browser.find_element_by_css_selector(".navbar-brand") self.assertEqual("Formalign.eu", brand_element.text) # She sees a form that says 'Paste in your alignment in FASTA format:' alignment_input = self.browser.find_element_by_css_selector("textarea#id_align_input") self.assertIsNotNone(self.browser.find_element_by_css_selector('label[for="id_align_input"]')) self.assertEqual( "Alignment (FASTA, clustalw, stockholm or phylip)", alignment_input.get_attribute("placeholder") ) # She sees two radio buttons for DNA and protein dna_button = self.browser.find_element_by_css_selector("input#id_seq_type_1") self.assertIsNotNone(dna_button) protein_button = self.browser.find_element_by_css_selector("input#id_seq_type_0") self.assertIsNotNone(protein_button) # She sees that the DNA button is selected by default self.assertEqual(dna_button.is_selected(), True) # She clicks the Protein radio button and sees that it gets selected and the DNA button gets unselected protein_button.click() # Wait for Firefox time.sleep(self.sleep) self.assertEqual(protein_button.is_selected(), True) self.assertEqual(dna_button.is_selected(), False) # She pastes in a protein alignment to see what happens alignment_string = file_to_string("spa_protein_alignment.fasta") pyperclip.copy(alignment_string) alignment_input = self.browser.find_element_by_css_selector("textarea#id_align_input") alignment_input.send_keys(Keys.CONTROL, "v") self.browser.find_element_by_id("submit-align").click() # Wait for Firefox time.sleep(self.sleep * 5) # She is redirected to a page showing the submitted sequences from her alignment and a simple consensus sequence self.assertEqual(self.browser.title, "Formalign.eu Sequence Display", self.browser.title) seq_content = self.browser.find_elements_by_css_selector(".query_seq_display") self.assertIsNotNone(seq_content) for f in seq_content: self.assertTrue(len(f.text) <= 80) first_seq_info = self.browser.find_elements_by_css_selector(".query_seq_meta")[0] self.assertEqual( "NP_175717 NP_175717.1 SPA1-related 4 protein [Arabidopsis thaliana].:", first_seq_info.text, first_seq_info.text, ) first_seq_content = self.browser.find_elements_by_css_selector(".query_seq_display")[0] self.assertIsNotNone(first_seq_content) self.assertEqual(first_seq_content.text, "-" * 80) consensus_seq = self.browser.find_elements_by_xpath('//div[@class="query_seq bg-color-body"]')[ -1 ].find_elements_by_xpath('./p[@class="query_seq_display"]')[0] self.assertIsNotNone(consensus_seq) cons_seq = file_to_string("consensus.txt") self.assertEqual(consensus_seq.text, cons_seq[:80]) consensus_meta = self.browser.find_elements_by_xpath('//h3[@class="query_seq_meta bg-color-body"]')[-1] self.assertEqual(consensus_meta.text, "consensus 70%:") # She is happy with the result, sees a "Render" button and clicks it. render_button = self.browser.find_element_by_css_selector("button#render-align") self.assertIsNotNone(render_button) render_button.click() # Wait for Firefox time.sleep(self.sleep * 10) # She is redirected to the alignment display page self.assertEqual("Formalign.eu Alignment Display", self.browser.title, self.browser.title) # She sees the alignment displayed with 80 characters per line in blocks of 10 with sequence ids s0 = self.browser.find_elements_by_xpath('//tr[@class="al_ln"]')[10].find_elements_by_xpath( './td[@class="residue S0"]' ) s1 = self.browser.find_elements_by_xpath('//tr[@class="al_ln"]')[10].find_elements_by_xpath( './td[@class="residue S1"]' ) self.assertEqual(len(s0) + len(s1), 80) sep = self.browser.find_elements_by_xpath('//tr[@class="al_ln"]')[10].find_elements_by_xpath( './td[@class="block_sep"]' ) self.assertEqual(len(sep), 8) # She is quite happy with the result and decides to try with another alignment so she navigates back to the # home page home_button = self.browser.find_element_by_css_selector(".navbar-brand") home_button.click() # Wait for Firefox time.sleep(self.sleep * 2) self.assertEqual("Formalign.eu Home", self.browser.title, self.browser.title) # She wants to upload a protein stockholm alignment this time from a file # She clicks the Protein radio button and sees that it gets selected and the DNA button gets unselected protein_button = self.browser.find_element_by_css_selector("input#id_seq_type_0") protein_button.click() self.assertEqual(protein_button.is_selected(), True)
def test_index(self): """ Tests index page """ # Lambda user is a biologist who has to make a nice figure containing a multiple alignment for a presentation. # She visits the formalign.eu site. r = self.client.get(self.url) csrftoken = self.client.cookies["csrftoken"] index = html.parse(StringIO(r.text)).getroot() title = index.cssselect('title[id="head-title"]') brand = index.cssselect('a[class="navbar-brand"]') align_input = index.cssselect('textarea[id="id_align_input"]') prot_button = index.cssselect('input[id="id_seq_type_0"]') prot_button_label = index.cssselect('label[for="id_seq_type_0"]') dna_button = index.cssselect('input[id="id_seq_type_1"]') # page displays no error message self.assertEqual(r.status_code, 200, r.status_code) # User sees she's on the right page because she can see the name of the site in the title and the brand. self.assertEqual("Formalign.eu Home", title[0].text_content(), title[0].text_content()) self.assertEqual(self.url + "/", r.url, r.url) self.assertEqual("Formalign.eu", brand[0].text_content(), brand[0].text_content()) # She sees a form that says 'Paste in your alignment' self.assertEqual( "Paste in your alignment:(FASTA, clustalw, stockholm or phylip)", align_input[0].label.text_content(), align_input[0].label.text_content(), ) # There's a textarea with a placeholder saying 'Alignment' self.assertEqual( "Alignment (FASTA, clustalw, stockholm or phylip)", align_input[0].attrib.get("placeholder"), align_input[0].attrib.get("placeholder"), ) # She sees two radio buttons for DNA and protein self.assertEqual( "Input sequence type:", prot_button[0].label.text_content(), prot_button[0].label.text_content() ) self.assertEqual(" Protein", prot_button_label[1].text_content(), prot_button_label[1].text_content()) self.assertEqual(" DNA", dna_button[0].label.text_content(), dna_button[0].label.text_content()) # She sees that the DNA button is selected by default self.assertTrue(prot_button[0].checkable, "Protein button is not checkable") self.assertFalse(prot_button[0].checked, "Protein button was checked by default") self.assertTrue(dna_button[0].checkable, "DNA button is not checkable") self.assertTrue(dna_button[0].checked, "DNA button was not checked by default") # She checks the protein button and pastes in an alignment alignment_string = file_to_string("spa_protein_alignment.fasta") self.client.headers.update({"referer": self.url}) r = self.client.post( self.url, data={"csrfmiddlewaretoken": csrftoken, "seq_type": "Protein", "align_input": alignment_string} ) self.assertEqual(r.status_code, 200, r.status_code) display = html.parse(StringIO(r.text)).getroot() title = display.cssselect('title[id="head-title"]') # She is redirected to the sequence display page self.assertEqual("Formalign.eu Sequence Display", title[0].text_content(), title[0].text_content()) self.assertEqual( "%s/query-sequences" % self.url, "/".join(r.url.split("/")[:-2]), "/".join(r.url.split("/")[:-2]) )
def test_alignment_display(self): """ Tests alignment display page """ # User visits home page, submits a protein alignment and renders it self.client.get(self.url) csrftoken = self.client.cookies["csrftoken"] alignment_string = file_to_string("spa_protein_alignment.fasta") self.client.headers.update({"referer": self.url}) r = self.client.post( self.url, data={"csrfmiddlewaretoken": csrftoken, "seq_type": "Protein", "align_input": alignment_string} ) render_form = html.parse(StringIO(r.text)).getroot().cssselect('form[id="render"]') r = self.client.get(self.url + render_form[0].attrib.get("action")) # She is redirected to the render page self.assertEqual(r.status_code, 200, r.status_code) align = html.parse(StringIO(r.text)).getroot() title = align.cssselect('title[id="head-title"]') self.assertEqual("Formalign.eu Alignment Display", title[0].text_content(), title[0].text_content()) self.assertEqual( "%s/align-display" % self.url, "/".join(r.url.split("/")[:-2]), "/".join(r.url.split("/")[:-2]) ) # She sees the alignment displayed with 80 characters per line in blocks of 10 with sequence ids seqs_meta = file_to_string("spa_protein_alignment_meta.txt").splitlines() tables = align.find_class("align_table") for nr, t in enumerate(tables): lines = t.find_class("al_ln") for i, l in enumerate(lines): self.assertEqual("seq_id", l[0].attrib.get("class"), l[0].attrib.get("class")) self.assertEqual(seqs_meta[i], l[0].text_content(), l[0].text_content()) self.assertTrue(len(l[1:]) <= 89, len(l[1:])) self.assertEqual("display_artifact", l[-1].attrib.get("class")) if len(l[1:]) >= 12: for j in range(1, len(l[1:]) % 10): self.assertEqual( "block_sep", l[j * 11].attrib.get("class"), "line number: %s, line length: %s, column: %s" % (i, len(l), format(j * 11)), ) for k in range(j * 11 - 10, j * 11): self.assertTrue( l[k].attrib.get("class") == "residue S0" or l[k].attrib.get("class") == "residue S1", "class: %s, table: %s, line: %s, column: %s" % (l[k].attrib.get("class"), nr, i, k), ) else: for j in range(1, len(l)): self.assertTrue( l[j].attrib.get("class") == "residue S0" or l[j].attrib.get("class") == "residue S1", l[j].attrib.get("class"), ) # She is quite happy with the result and decides to navigate back to the home page home_button = align.cssselect('a[class="navbar-brand"]') self.assertEqual("Formalign.eu", home_button[0].text_content(), home_button[0].text_content()) r = self.client.get(self.url + home_button[0].attrib.get("href")) self.assertEqual(r.status_code, 200, r.status_code) home = html.parse(StringIO(r.text)).getroot() title = home.cssselect('title[id="head-title"]') # User sees she's that she's back on the home page she can see the name of the site in the title and the brand. self.assertEqual("Formalign.eu Home", title[0].text_content(), title[0].text_content()) self.assertEqual(self.url + "/", r.url, r.url)