Skip to content

Commit ae07659

Browse files
authored
Merge pull request #657 from Lazy-poet/test-cases
Improve test coverage
2 parents 50af705 + b5706e3 commit ae07659

7 files changed

Lines changed: 169 additions & 28 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* eslint-disable no-unused-vars */
2+
/* eslint-disable no-undef */
3+
import { render, screen, fireEvent } from '@testing-library/react';
4+
import { Form } from '../form';
5+
import { AMINO_ACID_SEQUENCE } from './mock_data/sequences';
6+
import data from './mock_data/databases.json';
7+
import userEvent from '@testing-library/user-event';
8+
import '@testing-library/jest-dom/extend-expect';
9+
import '@testing-library/react/dont-cleanup-after-each';
10+
11+
export const setMockJSONResult = (result) => {
12+
global.$.getJSON = (_, cb) => cb(result);
13+
};
14+
describe('ADVANCED PARAMETERS', () => {
15+
const getInputElement = () => screen.getByRole('textbox', { name: '' });
16+
test('should not render the link to advanced parameters modal if blast algorithm is unknown', () => {
17+
setMockJSONResult(data);
18+
const {container } =render(<Form onSequenceTypeChanged={() => { }
19+
} />);
20+
const modalButton = container.querySelector('[data-target="#help"]');
21+
expect(modalButton).toBeNull();
22+
});
23+
test('should render the link to advanced parameters modal if blast algorithm is known', () => {
24+
setMockJSONResult(data);
25+
const {container } =render(<Form onSequenceTypeChanged={() => { }
26+
} />);
27+
28+
const inputEl = getInputElement();
29+
// populate search and select dbs to determine blast algorithm
30+
fireEvent.change(inputEl, { target: { value: AMINO_ACID_SEQUENCE } });
31+
const proteinSelectAllBtn = screen.getByRole('heading', { name: /protein databases/i }).parentElement.querySelector('button');
32+
fireEvent.click(proteinSelectAllBtn);
33+
const modalButton = container.querySelector('[data-target="#help"]');
34+
expect(modalButton).not.toBeNull();
35+
});
36+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export const AMINO_ACID_SEQUENCE = `MNTLWLSLWDYPGKLPLNFMVFDTKDDLQAAYWRDPYSIPLAVIFEDPQPISQRLIYEIR
2+
TNPSYTLPPPPTKLYSAPISCRKNKTGHWMDDILSIKTGESCPVNNYLHSGFLALQMITD
3+
ITKIKLENSDVTIPDIKLIMFPKEPYTADWMLAFRVVIPLYMVLALSQFITYLLILIVGE
4+
KENKIKEGMKMMGLNDSVF
5+
>SI2.2.0_13722 locus=Si_gnF.scaffold06207[1925625..1928536].pep_1 quality=100.00
6+
MSANRLNVLVTLMLAVALLVTESGNAQVDGYLQFNPKRSAVSSPQKYCGKKLSNALQIIC
7+
DGVYNSMFKKSGQDFPPQNKRHIAHRINGNEEESFTTLKSNFLNWCVEVYHRHYRFVFVS
8+
EMEMADYPLAYDISPYLPPFLSRARARGMLDGRFAGRRYRRESRGIHEECCINGCTINEL
9+
TSYCGP
10+
`;
11+
export const NUCLEOTIDE_SEQUENCE = `ATGAATACCCTCTGGCTCTCTTTATGGGATTATCCCGGTAAGCTTCCCTTAAACTTCATG
12+
GTGTTTGACACGAAGGATGATCTGCAAGCAGCGTATTGGAGAGATCCTTACAGCATACCT
13+
CTGGCAGTTATCTTCGAGGACCCCCAACCGATATCACAGCGACTTATATATGAAATTAGG
14+
ACGAATCCTTCATACACTTTGCCGCCACCGCCAACCAAATTGTATTCTGCTCCGATCAGT
15+
TGTCGAAAGAATAAAACTGGTCACTGGATGGACGACATTTTATCGATAAAAACCGGTGAA
16+
TCTTGTCCCGTTAACAATTACTTGCATTCTGGCTTCTTGGCTCTGCAAATGATAACGGAT
17+
ATCACAAAGATAAAATTGGAAAATTCTGACGTGACAATACCGGATATTAAACTCATAATG
18+
TTTCCTAAAGAGCCGTATACCGCTGACTGGATGCTGGCCTTCAGAGTTGTTATTCCGCTT
19+
TACATGGTCTTGGCTCTCTCGCAATTTATCACTTATCTTCTGATCCTAATAGTTGGCGAG
20+
AAGGAAAATAAGATTAAAGAGGGAATGAAGATGATGGGCTTAAATGATTCTGTGTTT
21+
>SI2.2.0_13722 Si_gnF.scaffold06207[1925625..1928536].pep_1
22+
ATGTCCGCGAATCGATTGAACGTGCTGGTGACCCTGATGCTCGCCGTCGCGCTTCTTGTG
23+
ACGGAATCAGGAAATGCACAGGTGGATGGCTATCTCCAATTCAACCCAAAGCGATCCGCC
24+
GTGAGCTCGCCGCAGAAGTATTGCGGCAAAAAGCTTTCTAATGCTCTACAGATAATCTGT
25+
GATGGCGTGTACAATTCCATGTTTAAGAAGAGTGGTCAAGATTTTCCCCCGCAAAATAAG
26+
AGACACATAGCACACAGAATAAATGGGAATGAGGAAGAGAGCTTTACTACGTTAAAGTCG
27+
AATTTTTTAAACTGGTGTGTTGAAGTTTATCATCGTCACTACAGATTCGTTTTTGTTTCA
28+
GAGATGGAAATGGCCGATTACCCGCTCGCCTATGATATTTCCCCGTATCTTCCGCCGTTC
29+
CTGTCGCGAGCGAGGGCACGGGGAATGTTAGACGGTCGCTTCGCCGGCAGACGCTACCGA
30+
AGGGAGTCGCGGGGCATTCACGAGGAGTGTTGCATCAACGGATGTACGATAAACGAATTG
31+
ACCAGCTACTGCGGCCCC
32+
`;

public/js/tests/report.spec.js

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ const TestSidebar = ({ long }) => {
2525
/>;
2626
};
2727

28+
const clickCheckboxes = (checkboxes, count) => {
29+
Array.from(checkboxes).slice(0, count).forEach((checkbox) => {
30+
fireEvent.click(checkbox);
31+
});
32+
};
2833
describe('REPORT PAGE', () => {
34+
global.URL.createObjectURL = jest.fn();//.mockReturnValue('xyz.test');
35+
global.setTimeout = (cb) => cb();
2936
it('should render the report component with initial loading state', () => {
3037
render(<Report />);
3138
expect(screen.getByRole('heading', { name: 'BLAST-ing' })).toBeInTheDocument();
@@ -39,7 +46,7 @@ describe('REPORT PAGE', () => {
3946
});
4047
it('it should render the report page correctly if there\'s a response provided', () => {
4148
setMockJSONResult({ status: 200, responseJSON: shortResponseJSON });
42-
const { container } = render(<Report />);
49+
const { container } = render(<Report getCharacterWidth={jest.fn()} />);
4350
expect(container.querySelector('#results')).toBeInTheDocument();
4451

4552
});
@@ -63,18 +70,18 @@ describe('REPORT PAGE', () => {
6370
});
6471

6572
describe('LONG QUERIES (>12)', () => {
66-
73+
let container;
74+
beforeEach(() => {
75+
container = render(<TestSidebar long />).container;
76+
});
6777
it('should not show navigation links for long queries', () => {
68-
const { container } = render(<TestSidebar long />);
6978
expect(container.querySelectorAll('a[href^="#Query_"]').length).toBe(0);
7079
});
7180
it('should show only next button if on first query ', () => {
72-
render(<TestSidebar long />);
7381
expect(nextQueryButton()).toBeInTheDocument();
7482
expect(previousQueryButton()).not.toBeInTheDocument();
7583
});
7684
it('should show both previous and next buttons if not on first query', () => {
77-
render(<TestSidebar long />);
7885
const nextBtn = nextQueryButton();
7986
expect(nextBtn).toBeInTheDocument();
8087
fireEvent.click(nextBtn);
@@ -84,7 +91,6 @@ describe('REPORT PAGE', () => {
8491
});
8592
it('should show only previous button if on last query', () => {
8693
const { queries } = longResponseJSON;
87-
render(<TestSidebar long />);
8894
expect(nextQueryButton()).toBeInTheDocument();
8995
expect(previousQueryButton()).not.toBeInTheDocument();
9096

@@ -95,5 +101,55 @@ describe('REPORT PAGE', () => {
95101
expect(previousQueryButton()).toBeInTheDocument();
96102
});
97103
});
104+
105+
describe('DOWNLOAD LINKS', () => {
106+
let container;
107+
beforeEach(() => {
108+
setMockJSONResult({ status: 200, responseJSON: shortResponseJSON });
109+
container = render(<Report getCharacterWidth={jest.fn()} />).container;
110+
});
111+
describe('ALIGNMENT DOWNLOAD', () => {
112+
it('should generate a blob url and filename for downloading alignment of all hits on render', () => {
113+
const alignment_download_link = container.querySelector('.download-alignment-of-all');
114+
const expected_num_hits = container.querySelectorAll('.hit-links input[type="checkbox"]').length;
115+
const file_name = `alignment-${expected_num_hits}_hits.txt`;
116+
expect(alignment_download_link.download).toEqual(file_name);
117+
expect(alignment_download_link.hred).not.toEqual('#');
118+
});
119+
it('link for downloading alignment of specific number of selected hits should be disabled on initial load', () => {
120+
const alignment_download_link = container.querySelector('.download-alignment-of-selected');
121+
expect(alignment_download_link.classList.contains('disabled')).toBeTruthy();
122+
123+
});
124+
it('should generate a blob url and filename for downloading alignment of specific number of selected hits', () => {
125+
const alignment_download_link = container.querySelector('.download-alignment-of-selected');
126+
// QUERY ALL HIT LINKS CHECKBOXES
127+
const checkboxes = container.querySelectorAll('.hit-links input[type="checkbox"]');
128+
// SELECT 4 CHECKBOXES
129+
clickCheckboxes(checkboxes, 4);
130+
const file_name = 'alignment-4_hits.txt';
131+
expect(alignment_download_link.textContent).toEqual('Alignment of 4 selected hit(s)');
132+
expect(alignment_download_link.download).toEqual(file_name);
133+
});
134+
});
135+
136+
describe('FASTA DOWNLOAD', () => {
137+
let fasta_download_link;
138+
beforeEach(() => {
139+
fasta_download_link = container.querySelector('.download-fasta-of-selected');
140+
});
141+
it('link for downloading fasta of selected number of hits should be disabled on initial load', () => {
142+
expect(fasta_download_link.classList.contains('disabled')).toBeTruthy();
143+
});
144+
145+
it('link for downloading fasta of specific number of selected hits should be active after selection', () => {
146+
const checkboxes = container.querySelectorAll('.hit-links input[type="checkbox"]');
147+
// SELECT 5 CHECKBOXES
148+
clickCheckboxes(checkboxes, 5);
149+
expect(fasta_download_link.textContent).toEqual('FASTA of 5 selected hit(s)');
150+
});
151+
});
152+
});
98153
});
154+
99155
});

public/js/tests/search_query.spec.js

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,56 @@
33
import { render, screen, fireEvent } from '@testing-library/react';
44
import { SearchQueryWidget } from '../query';
55
import { Form } from '../form';
6-
import userEvent from '@testing-library/user-event';
6+
import { AMINO_ACID_SEQUENCE, NUCLEOTIDE_SEQUENCE } from './mock_data/sequences';
77
import '@testing-library/jest-dom/extend-expect';
88
import '@testing-library/react/dont-cleanup-after-each';
99

10-
export const AMINO_ACID_SEQUENCE = `MNTLWLSLWDYPGKLPLNFMVFDTKDDLQAAYWRDPYSIPLAVIFEDPQPISQRLIYEIR
11-
TNPSYTLPPPPTKLYSAPISCRKNKTGHWMDDILSIKTGESCPVNNYLHSGFLALQMITD
12-
ITKIKLENSDVTIPDIKLIMFPKEPYTADWMLAFRVVIPLYMVLALSQFITYLLILIVGE
13-
KENKIKEGMKMMGLNDSVF
14-
>SI2.2.0_13722 locus=Si_gnF.scaffold06207[1925625..1928536].pep_1 quality=100.00
15-
MSANRLNVLVTLMLAVALLVTESGNAQVDGYLQFNPKRSAVSSPQKYCGKKLSNALQIIC
16-
DGVYNSMFKKSGQDFPPQNKRHIAHRINGNEEESFTTLKSNFLNWCVEVYHRHYRFVFVS
17-
EMEMADYPLAYDISPYLPPFLSRARARGMLDGRFAGRRYRRESRGIHEECCINGCTINEL
18-
TSYCGP
19-
`;
10+
let container;
11+
let inputEl;
12+
2013
describe('SEARCH COMPONENT', () => {
21-
const getInputElement = () => screen.getByRole('textbox', { name: '' });
14+
beforeEach(() => {
15+
container = render(<Form onSequenceTypeChanged={() => { }
16+
} />).container;
17+
inputEl = screen.getByRole('textbox', { name: '' });
18+
});
19+
2220
test('should render the search component textarea', () => {
23-
render(<SearchQueryWidget onSequenceTypeChanged={() => { }
24-
} />);
25-
const el = getInputElement();
26-
expect(el).toHaveClass('form-control');
21+
expect(inputEl).toHaveClass('form-control');
2722
});
2823

2924
test('clear button should only become visible if textarea is not empty', () => {
30-
render(<SearchQueryWidget onSequenceTypeChanged={() => { }
31-
} />);
3225
const getButtonWrapper = () => screen.getByRole('button', { name: /clear query sequence\(s\)\./i }).parentElement;
3326
expect(getButtonWrapper()).toHaveClass('hidden');
34-
const inputEl = getInputElement();
3527
fireEvent.change(inputEl, { target: { value: AMINO_ACID_SEQUENCE } });
3628
expect(getButtonWrapper()).not.toHaveClass('hidden');
3729
fireEvent.change(inputEl, { target: { value: '' } });
3830
expect(getButtonWrapper()).toHaveClass('hidden');
31+
});
3932

33+
test('should correctly detect the amino-acid sequence type and show notification', () => {
34+
// populate search
35+
fireEvent.change(inputEl, { target: { value: AMINO_ACID_SEQUENCE } });
36+
const activeNotification = container.querySelector('.notification.active');
37+
expect(activeNotification.id).toBe('protein-sequence-notification');
38+
const alertWrapper = activeNotification.children[0];
39+
expect(alertWrapper).toHaveTextContent('Detected: amino-acid sequence(s).');
40+
});
41+
42+
test('should correctly detect the nucleotide sequence type and show notification', () => {
43+
// populate search
44+
fireEvent.change(inputEl, { target: { value: NUCLEOTIDE_SEQUENCE } });
45+
const activeNotification = container.querySelector('.notification.active');
46+
const alertWrapper = activeNotification.children[0];
47+
expect(activeNotification.id).toBe('nucleotide-sequence-notification');
48+
expect(alertWrapper).toHaveTextContent('Detected: nucleotide sequence(s).');
49+
});
50+
51+
test('should correctly detect the mixed sequences and show error notification', () => {
52+
fireEvent.change(inputEl, { target: { value: `${NUCLEOTIDE_SEQUENCE}${AMINO_ACID_SEQUENCE}` } });
53+
const activeNotification = container.querySelector('.notification.active');
54+
expect(activeNotification.id).toBe('mixed-sequence-notification');
55+
const alertWrapper = activeNotification.children[0];
56+
expect(alertWrapper).toHaveTextContent('Error: mixed nucleotide and amino-acid sequences detected.');
4057
});
4158
});

public/js/visualisation_helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ from 'underscore';
2-
2+
import d3 from 'd3';
33
export function get_colors_for_evalue(evalue, hits) {
44
var colors = d3.scale
55
.log()

0 commit comments

Comments
 (0)