blob: 91ebac93e59b557d580cd7196fbdadf5b6f8f8ea [file] [log] [blame]
Philipp Schrader175a93c2023-02-19 13:13:40 -08001/// <reference types="cypress" />
2
3function disableAlerts() {
4 cy.get('#block_alerts').check({force: true}).should('be.checked');
5}
6
7function switchToTab(tabName) {
8 cy.contains('.nav-link', tabName).click();
9}
10
11function headerShouldBe(text) {
12 cy.get('.header').should('have.text', text);
13}
14
15function clickButton(buttonName) {
16 cy.contains('button', buttonName).click();
17}
18
19function setInputTo(fieldSelector, value) {
20 cy.get(fieldSelector).type('{selectAll}' + value);
21}
22
23// Moves the nth slider left or right. A positive "adjustBy" value moves the
24// slider to the right. A negative value moves the slider to the left.
25//
26// negative/left <--- 0 ---> positive/right
27function adjustNthSliderBy(n, adjustBy) {
28 let element = cy.get('input[type=range]').eq(n);
29 element.scrollIntoView();
30 element.invoke('val').then((currentValue) => {
31 // We need to query for the slider here again because `invoke('val')` above
32 // somehow invalidates further calls to `val`.
33 cy.get('input[type=range]')
34 .eq(n)
35 .invoke('val', currentValue + adjustBy)
36 .trigger('change');
37 });
38}
39
40// Asserts that the field on the "Submit and Review" screen has a specific
41// value.
42function expectReviewFieldToBe(fieldName, expectedValue) {
43 expectNthReviewFieldToBe(fieldName, 0, expectedValue);
44}
45
46// Asserts that the n'th instance of a field on the "Submit and Review"
47// screen has a specific value.
48function expectNthReviewFieldToBe(fieldName, n, expectedValue) {
49 getNthReviewField(fieldName, n).should(
50 'have.text',
51 `${fieldName}: ${expectedValue}`
52 );
53}
54
55function getNthReviewField(fieldName, n) {
56 let element = cy.get('li').filter(`:contains("${fieldName}: ")`).eq(n);
57 element.scrollIntoView();
58 return element;
59}
60
61before(() => {
62 cy.visit('/');
63 disableAlerts();
64 cy.title().should('eq', 'FRC971 Scouting Application');
Philipp Schrader175a93c2023-02-19 13:13:40 -080065});
66
67beforeEach(() => {
68 cy.visit('/');
69 disableAlerts();
70});
71
72describe('Scouting app tests', () => {
73 it('should: show matches in chronological order.', () => {
74 headerShouldBe('Matches');
75 cy.get('.badge').eq(0).contains('Quals Match 1');
76 cy.get('.badge').eq(1).contains('Quals Match 2');
77 cy.get('.badge').eq(2).contains('Quals Match 3');
78 cy.get('.badge').eq(9).contains('Quals Match 10');
79 cy.get('.badge').eq(72).contains('Quarter Final 1 Match 1');
80 cy.get('.badge').eq(73).contains('Quarter Final 2 Match 1');
81 cy.get('.badge').eq(74).contains('Quarter Final 3 Match 1');
82 cy.get('.badge').eq(75).contains('Quarter Final 4 Match 1');
83 cy.get('.badge').eq(76).contains('Quarter Final 1 Match 2');
84 cy.get('.badge').eq(82).contains('Semi Final 1 Match 1');
85 cy.get('.badge').eq(83).contains('Semi Final 2 Match 1');
86 cy.get('.badge').eq(84).contains('Semi Final 1 Match 2');
87 cy.get('.badge').eq(85).contains('Semi Final 2 Match 2');
88 cy.get('.badge').eq(89).contains('Final 1 Match 3');
89 });
90
91 it('should: prefill the match information.', () => {
92 headerShouldBe('Matches');
93
94 // On the 87th row of matches (index 86) click on the second team
95 // (index 1) which resolves to team 5254 in semi final 2 match 3.
96 cy.get('button.match-item')
97 .eq(86 * 6 + 1)
98 .click();
99
100 headerShouldBe('Team Selection');
101 cy.get('#match_number').should('have.value', '3');
102 cy.get('#team_number').should('have.value', '5254');
103 cy.get('#set_number').should('have.value', '2');
104 cy.get('#comp_level').should('have.value', '3: sf');
105 });
106
107 it('should: error on unknown match.', () => {
108 switchToTab('Data Entry');
109 headerShouldBe('Team Selection');
110
111 // Pick a match that doesn't exist in the 2016nytr match list.
112 setInputTo('#match_number', '3');
113 setInputTo('#team_number', '971');
114
115 // Click Next until we get to the submit screen.
116 for (let i = 0; i < 5; i++) {
117 clickButton('Next');
118 }
119 headerShouldBe('Review and Submit');
120
121 // Attempt to submit and validate the error.
122 clickButton('Submit');
123 cy.get('.error_message').contains(
124 'Failed to find team 971 in match 3 in the schedule.'
125 );
126 });
127
128 // Make sure that each page on the Entry tab has both "Next" and "Back"
129 // buttons. The only screens exempted from this are the first page and the
130 // last page.
131 it('should: have forwards and backwards buttons.', () => {
132 switchToTab('Data Entry');
133
134 const expectedOrder = [
135 'Team Selection',
136 'Auto',
137 'TeleOp',
138 'Climb',
139 'Other',
140 'Review and Submit',
141 ];
142
143 // Go forward through the screens.
144 for (let i = 0; i < expectedOrder.length; i++) {
145 headerShouldBe(expectedOrder[i]);
146 if (i != expectedOrder.length - 1) {
147 clickButton('Next');
148 }
149 }
150
151 // Go backwards through the screens.
152 for (let i = 0; i < expectedOrder.length; i++) {
153 headerShouldBe(expectedOrder[expectedOrder.length - i - 1]);
154 if (i != expectedOrder.length - 1) {
155 clickButton('Back');
156 }
157 }
158 });
159
160 it('should: review and submit correct data.', () => {
161 switchToTab('Data Entry');
162
163 // Submit scouting data for a random team that attended 2016nytr.
164 headerShouldBe('Team Selection');
165 setInputTo('#match_number', '2');
166 setInputTo('#team_number', '5254');
167 setInputTo('#set_number', '42');
168 cy.get('#comp_level').select('Semi Finals');
169 clickButton('Next');
170
171 headerShouldBe('Auto');
172 cy.get('#quadrant3').check();
173 clickButton('Next');
174
175 headerShouldBe('TeleOp');
176 clickButton('Next');
177
178 headerShouldBe('Climb');
179 cy.get('#high').check();
180 clickButton('Next');
181
182 headerShouldBe('Other');
183 adjustNthSliderBy(0, 3);
184 adjustNthSliderBy(1, 1);
185 cy.get('#no_show').check();
186 cy.get('#mechanically_broke').check();
187 setInputTo('#comment', 'A very useful comment here.');
188 clickButton('Next');
189
190 headerShouldBe('Review and Submit');
191 cy.get('.error_message').should('have.text', '');
192
193 // Validate Team Selection.
194 expectReviewFieldToBe('Match number', '2');
195 expectReviewFieldToBe('Team number', '5254');
196 expectReviewFieldToBe('SetNumber', '42');
197 expectReviewFieldToBe('Comp Level', 'Semi Finals');
198
199 // Validate Auto.
200 expectNthReviewFieldToBe('Upper Shots Made', 0, '0');
201 expectNthReviewFieldToBe('Lower Shots Made', 0, '0');
202 expectNthReviewFieldToBe('Missed Shots', 0, '0');
203 expectReviewFieldToBe('Quadrant', '3');
204
205 // Validate TeleOp.
206 expectNthReviewFieldToBe('Upper Shots Made', 1, '0');
207 expectNthReviewFieldToBe('Lower Shots Made', 1, '0');
208 expectNthReviewFieldToBe('Missed Shots', 1, '0');
209
210 // Validate Climb.
211 expectReviewFieldToBe('Climb Level', 'High');
212
213 // Validate Other.
214 expectReviewFieldToBe('Defense Played On Rating', '3');
215 expectReviewFieldToBe('Defense Played Rating', '1');
216 expectReviewFieldToBe('No show', 'true');
217 expectReviewFieldToBe('Never moved', 'false');
218 expectReviewFieldToBe('Battery died', 'false');
219 expectReviewFieldToBe('Broke (mechanically)', 'true');
220 expectReviewFieldToBe('Comments', 'A very useful comment here.');
221
222 clickButton('Submit');
223 headerShouldBe('Success');
224 });
225
226 it('should: load all images successfully.', () => {
227 switchToTab('Data Entry');
228
229 // Get to the Auto display with the field pictures.
230 headerShouldBe('Team Selection');
231 clickButton('Next');
232 headerShouldBe('Auto');
233
234 // We expect 2 fully loaded images for each of the orientations.
235 // 2 images for the original orientation and 2 images for the flipped orientation.
236 for (let i = 0; i < 2; i++) {
237 cy.get('img').should(($imgs) => {
238 for (const $img of $imgs) {
239 expect($img.naturalWidth).to.be.greaterThan(0);
240 }
241 });
242 clickButton('Flip');
243 }
244 });
245
246 it('should: submit note scouting for multiple teams', () => {
247 // Navigate to Notes Page.
248 switchToTab('Notes');
249 headerShouldBe('Notes');
250
251 // Add first team.
252 setInputTo('#team_number_notes', '1234');
253 clickButton('Select');
254
255 // Add note and select keyword for first team.
256 cy.get('#team-key-1').should('have.text', '1234');
257 setInputTo('#text-input-1', 'Good Driving');
258 cy.get('#good_driving_0').click();
259
260 // Navigate to add team selection and add another team.
261 clickButton('Add team');
262 setInputTo('#team_number_notes', '1235');
263 clickButton('Select');
264
265 // Add note and select keyword for second team.
266 cy.get('#team-key-2').should('have.text', '1235');
267 setInputTo('#text-input-2', 'Bad Driving');
268 cy.get('#bad_driving_1').click();
269
270 // Submit Notes.
271 clickButton('Submit');
272 cy.get('#team_number_label').should('have.text', ' Team Number ');
273 });
274
275 it('should: switch note text boxes with keyboard shortcuts', () => {
276 // Navigate to Notes Page.
277 switchToTab('Notes');
278 headerShouldBe('Notes');
279
280 // Add first team.
281 setInputTo('#team_number_notes', '1234');
282 clickButton('Select');
283
284 // Add second team.
285 clickButton('Add team');
286 setInputTo('#team_number_notes', '1235');
287 clickButton('Select');
288
289 // Add third team.
290 clickButton('Add team');
291 setInputTo('#team_number_notes', '1236');
292 clickButton('Select');
293
294 for (let i = 1; i <= 3; i++) {
295 // Press Control + i
296 cy.get('body').type(`{ctrl}${i}`);
297
298 // Expect text input to be focused.
299 cy.focused().then(($element) => {
300 expect($element).to.have.id(`text-input-${i}`);
301 });
302 }
303 });
304
305 it('should: submit driver ranking', () => {
306 // Navigate to Driver Ranking Page.
307 switchToTab('Driver Ranking');
308 headerShouldBe('Driver Ranking');
309
310 // Input match and team numbers.
311 setInputTo('#match_number_selection', '11');
312 setInputTo('#team_input_0', '123');
313 setInputTo('#team_input_1', '456');
314 setInputTo('#team_input_2', '789');
315 clickButton('Select');
316
317 // Verify match and team key input.
318 cy.get('#match_number_heading').should('have.text', 'Match #11');
319 cy.get('#team_key_label_0').should('have.text', ' 123 ');
320 cy.get('#team_key_label_1').should('have.text', ' 456 ');
321 cy.get('#team_key_label_2').should('have.text', ' 789 ');
322
323 // Rank teams.
324 cy.get('#up_button_2').click();
325 cy.get('#down_button_0').click();
326
327 // Verify ranking change.
328 cy.get('#team_key_label_0').should('have.text', ' 789 ');
329 cy.get('#team_key_label_1').should('have.text', ' 123 ');
330 cy.get('#team_key_label_2').should('have.text', ' 456 ');
331
332 // Submit.
333 clickButton('Submit');
334 });
335});