blob: 7157880c9ff28e4414342da432e7d7e7a19578ed [file] [log] [blame]
Philipp Schrader175a93c2023-02-19 13:13:40 -08001/// <reference types="cypress" />
2
Philipp Schradere11114f2023-04-15 17:04:25 -07003// On the 87th row of matches (index 86) click on the second team
4// (index 1) which resolves to team 5254 in semi final 2 match 3.
5const SEMI_FINAL_2_MATCH_3_TEAM_5254 = 86 * 6 + 1;
6
7// On the 1st row of matches (index 0) click on the fourth team
8// (index 3) which resolves to team 3990 in quals match 1.
9const QUALS_MATCH_1_TEAM_3990 = 0 * 6 + 3;
10
Filip Kujawac1ded372023-05-27 14:33:43 -070011// On the 2st row of matches (index 1) click on the fourth team
12// (index 3) which resolves to team 4481 in quals match 1.
13const QUALS_MATCH_2_TEAM_4481 = 1 * 6 + 3;
14
Philipp Schrader175a93c2023-02-19 13:13:40 -080015function disableAlerts() {
16 cy.get('#block_alerts').check({force: true}).should('be.checked');
17}
18
19function switchToTab(tabName) {
20 cy.contains('.nav-link', tabName).click();
21}
22
23function headerShouldBe(text) {
24 cy.get('.header').should('have.text', text);
25}
26
27function clickButton(buttonName) {
28 cy.contains('button', buttonName).click();
29}
30
31function setInputTo(fieldSelector, value) {
32 cy.get(fieldSelector).type('{selectAll}' + value);
33}
34
35// Moves the nth slider left or right. A positive "adjustBy" value moves the
36// slider to the right. A negative value moves the slider to the left.
37//
38// negative/left <--- 0 ---> positive/right
39function adjustNthSliderBy(n, adjustBy) {
40 let element = cy.get('input[type=range]').eq(n);
41 element.scrollIntoView();
42 element.invoke('val').then((currentValue) => {
43 // We need to query for the slider here again because `invoke('val')` above
44 // somehow invalidates further calls to `val`.
45 cy.get('input[type=range]')
46 .eq(n)
47 .invoke('val', currentValue + adjustBy)
48 .trigger('change');
49 });
50}
51
52// Asserts that the field on the "Submit and Review" screen has a specific
53// value.
54function expectReviewFieldToBe(fieldName, expectedValue) {
55 expectNthReviewFieldToBe(fieldName, 0, expectedValue);
56}
57
58// Asserts that the n'th instance of a field on the "Submit and Review"
59// screen has a specific value.
60function expectNthReviewFieldToBe(fieldName, n, expectedValue) {
61 getNthReviewField(fieldName, n).should(
62 'have.text',
63 `${fieldName}: ${expectedValue}`
64 );
65}
66
67function getNthReviewField(fieldName, n) {
68 let element = cy.get('li').filter(`:contains("${fieldName}: ")`).eq(n);
69 element.scrollIntoView();
70 return element;
71}
72
Filip Kujawac1ded372023-05-27 14:33:43 -070073function submitDataScouting(
74 matchButtonKey = SEMI_FINAL_2_MATCH_3_TEAM_5254,
75 teamNumber = 5254
76) {
77 // Click on a random team in the Match list. The exact details here are not
78 // important, but we need to know what they are. This could as well be any
79 // other team from any other match.
80 cy.get('button.match-item').eq(matchButtonKey).click();
81
82 // Select Starting Position.
83 headerShouldBe(teamNumber + ' Init ');
84 cy.get('[type="radio"]').first().check();
85 clickButton('Start Match');
86
Emily Markovadcadcb62024-02-03 13:07:17 -080087 // Pick and Place Note in Auto.
88 clickButton('NOTE');
89 clickButton('AMP');
Filip Kujawac1ded372023-05-27 14:33:43 -070090
91 // Pick and Place Cube in Teleop.
92 clickButton('Start Teleop');
Emily Markovadcadcb62024-02-03 13:07:17 -080093 clickButton('NOTE');
Emily Markovacd156942024-04-07 19:32:28 -070094 clickButton('SPEAKER AMPLIFIED');
Filip Kujawac1ded372023-05-27 14:33:43 -070095
96 // Robot dead and revive.
97 clickButton('DEAD');
98 clickButton('Revive');
99
100 // Endgame.
101 clickButton('Endgame');
Emily Markovadcadcb62024-02-03 13:07:17 -0800102 cy.contains(/Harmony/).click();
Filip Kujawac1ded372023-05-27 14:33:43 -0700103
104 clickButton('End Match');
Emily Markovaf2743e82024-09-21 14:14:04 -0700105
106 clickButton('UNDO');
107 clickButton('End Match');
108
Filip Kujawac1ded372023-05-27 14:33:43 -0700109 headerShouldBe(teamNumber + ' Review and Submit ');
Emily Markovaf2743e82024-09-21 14:14:04 -0700110
Filip Kujawac1ded372023-05-27 14:33:43 -0700111 cy.get('#review_data li')
112 .eq(0)
113 .should('have.text', ' Started match at position 1 ');
Philipp Schrader3d7dedc2024-03-16 16:27:25 -0700114 cy.get('#review_data li').eq(1).should('have.text', ' Picked up Note ');
Filip Kujawac1ded372023-05-27 14:33:43 -0700115 cy.get('#review_data li')
116 .last()
117 .should(
118 'have.text',
Emily Markova6079e2f2024-02-17 13:17:24 -0800119 ' Ended Match; stageType: kHARMONY, trapNote: false, spotlight: false '
Filip Kujawac1ded372023-05-27 14:33:43 -0700120 );
Emily Markovaf2743e82024-09-21 14:14:04 -0700121 // Ensure that the penalties action is only submitted once.
Emily Markova4677cb62024-09-25 20:23:48 -0700122 cy.get('#review_data li:contains("Penalties")').its('length').should('eq', 1);
Filip Kujawac1ded372023-05-27 14:33:43 -0700123
124 clickButton('Submit');
125 headerShouldBe(teamNumber + ' Success ');
126}
Emily Markova7b786402024-01-24 20:05:24 -0800127function visit(path) {
128 cy.visit(path, {
129 onBeforeLoad(win) {
130 // The service worker seems to interfere with Cypress somehow. There
131 // doesn't seem to be a proper fix for this issue. Work around it with
132 // this hack that disables the service worker.
133 // https://github.com/cypress-io/cypress/issues/16192#issuecomment-870421667
134 // https://github.com/cypress-io/cypress/issues/702#issuecomment-587127275
135 delete win.navigator.__proto__.serviceWorker;
136 },
137 });
138}
Filip Kujawac1ded372023-05-27 14:33:43 -0700139
Philipp Schrader175a93c2023-02-19 13:13:40 -0800140before(() => {
Emily Markova7b786402024-01-24 20:05:24 -0800141 visit('/');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800142 disableAlerts();
143 cy.title().should('eq', 'FRC971 Scouting Application');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800144});
145
146beforeEach(() => {
Emily Markova7b786402024-01-24 20:05:24 -0800147 visit('/');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800148 disableAlerts();
149});
150
151describe('Scouting app tests', () => {
152 it('should: show matches in chronological order.', () => {
153 headerShouldBe('Matches');
154 cy.get('.badge').eq(0).contains('Quals Match 1');
155 cy.get('.badge').eq(1).contains('Quals Match 2');
156 cy.get('.badge').eq(2).contains('Quals Match 3');
157 cy.get('.badge').eq(9).contains('Quals Match 10');
158 cy.get('.badge').eq(72).contains('Quarter Final 1 Match 1');
159 cy.get('.badge').eq(73).contains('Quarter Final 2 Match 1');
160 cy.get('.badge').eq(74).contains('Quarter Final 3 Match 1');
161 cy.get('.badge').eq(75).contains('Quarter Final 4 Match 1');
162 cy.get('.badge').eq(76).contains('Quarter Final 1 Match 2');
163 cy.get('.badge').eq(82).contains('Semi Final 1 Match 1');
164 cy.get('.badge').eq(83).contains('Semi Final 2 Match 1');
165 cy.get('.badge').eq(84).contains('Semi Final 1 Match 2');
166 cy.get('.badge').eq(85).contains('Semi Final 2 Match 2');
167 cy.get('.badge').eq(89).contains('Final 1 Match 3');
168 });
169
Philipp Schrader8702b782023-04-15 17:33:37 -0700170 it('should: prevent users from enter invalid match information.', () => {
171 switchToTab('Entry');
172 headerShouldBe(' Team Selection ');
173
174 setInputTo('#match_number', '1');
175 setInputTo('#team_number', '5254');
176 setInputTo('#set_number', '1');
177 cy.get('#comp_level').select('Qualifications');
178
179 cy.contains('button', 'Next').should('be.disabled');
180 });
181
Philipp Schradere1498852023-04-15 18:06:45 -0700182 it('should: allow users to scout non-existent matches when pre-scouting.', () => {
183 switchToTab('Entry');
184 headerShouldBe(' Team Selection ');
185 setInputTo('#team_number', '1');
186
187 // The default team information should be invalid.
188 cy.contains('button', 'Next').should('be.disabled');
189
190 // Click the checkmark to designate this as pre-scouting.
191 // We should now be able to continue scouting.
192 cy.get('#pre_scouting').click();
193 clickButton('Next');
194 headerShouldBe('1 Init ');
195 });
196
Emily Markova9c18e9c2024-04-03 20:06:27 -0700197 it('should: allow users to scout practice matches.', () => {
198 switchToTab('Entry');
199 headerShouldBe(' Team Selection ');
200 setInputTo('#team_number', '1');
201
202 // The default team information should be invalid.
203 cy.contains('button', 'Next').should('be.disabled');
204
205 // Click the checkmark to designate this as pre-scouting.
206 // We should now be able to continue scouting.
207 cy.get('#practice_match').click();
208 clickButton('Next');
209 headerShouldBe('1 Init ');
210 });
211
Emily Markova8e39f452023-12-23 12:17:30 -0800212 it('should: allow users to submit pit images.', () => {
213 switchToTab('Pit');
214 headerShouldBe('Pit Scouting');
215 setInputTo('#teamNumber', '971');
216
217 cy.get('#pitImage').selectFile('test_img_1.png');
218
219 clickButton('Submit');
220 headerShouldBe('Pit Scouting');
221 setInputTo('#teamNumber', '971');
222
223 cy.get('#pitImage').selectFile('test_img_2.png');
224
225 clickButton('Submit');
226 headerShouldBe('Pit Scouting');
227
228 switchToTab('View');
229
230 cy.get('[data-bs-toggle="dropdown"]').click();
231 cy.get('[id="pit_images_source_dropdown"]').click();
232 cy.get('table.table tbody th').should('contain', '971');
233 cy.get('img')
234 .first()
235 .should('be.visible')
236 .should('have.attr', 'src')
237 .should('include', 'test_img_1.png');
238 cy.get('img')
239 .last()
240 .should('be.visible')
241 .should('have.attr', 'src')
242 .should('include', 'test_img_2.png');
243 });
244
Philipp Schrader8702b782023-04-15 17:33:37 -0700245 it('should: let users enter match information manually.', () => {
Philipp Schrader75021f52023-04-09 21:14:13 -0700246 switchToTab('Entry');
Philipp Schrader2b334272023-04-11 21:27:36 -0700247 headerShouldBe(' Team Selection ');
Philipp Schrader75021f52023-04-09 21:14:13 -0700248
249 setInputTo('#match_number', '3');
250 setInputTo('#team_number', '5254');
251 setInputTo('#set_number', '2');
Philipp Schrader8702b782023-04-15 17:33:37 -0700252 cy.get('#comp_level').select('Semi Finals');
Philipp Schrader75021f52023-04-09 21:14:13 -0700253
254 clickButton('Next');
255
256 headerShouldBe('5254 Init ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800257 });
258
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800259 //TODO(FILIP): Verify last action when the last action header gets added.
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800260 it('should: be able to submit data scouting.', () => {
Filip Kujawac1ded372023-05-27 14:33:43 -0700261 submitDataScouting();
Philipp Schradere11114f2023-04-15 17:04:25 -0700262
263 // Now that the data is submitted, the button should be disabled.
264 switchToTab('Match List');
265 cy.get('button.match-item')
266 .eq(SEMI_FINAL_2_MATCH_3_TEAM_5254)
267 .should('be.disabled');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800268 });
269
Filip Kujawac1ded372023-05-27 14:33:43 -0700270 it('should: be able to delete data scouting entry', () => {
271 // Submit data to delete.
272 submitDataScouting(QUALS_MATCH_2_TEAM_4481, 4481);
273
274 switchToTab('View');
275
276 cy.get('[data-bs-toggle="dropdown"]').click();
277 cy.get('[id="stats_source_dropdown"]').click();
278
279 // Check that table contains data.
280 cy.get('table.table tbody td').should('contain', '4481');
281
282 // Find and click the delete button for the row containing team 4481.
283 cy.get('table.table tbody td')
284 .contains('4481')
285 .parent()
286 .find('[id^="delete_button_"]')
287 .click();
288 cy.on('window:confirm', () => true);
289
290 // Check that deleted data is not in table.
291 cy.get('table.table tbody').should('not.contain', '4481');
292 });
293
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800294 it('should: be able to return to correct screen with undo for pick and place.', () => {
Philipp Schradere11114f2023-04-15 17:04:25 -0700295 cy.get('button.match-item').eq(QUALS_MATCH_1_TEAM_3990).click();
Philipp Schrader2b334272023-04-11 21:27:36 -0700296
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800297 // Select Starting Position.
298 cy.get('[type="radio"]').first().check();
299 clickButton('Start Match');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800300
Emily Markovadcadcb62024-02-03 13:07:17 -0800301 // Pick up note.
302 clickButton('NOTE');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800303
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800304 // Undo that pick up.
305 clickButton('UNDO');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800306
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800307 // User should be back on pickup screen.
Philipp Schradere11114f2023-04-15 17:04:25 -0700308 headerShouldBe('3990 Pickup ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800309
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800310 // Check the same thing but for undoing place.
Emily Markovadcadcb62024-02-03 13:07:17 -0800311 clickButton('NOTE');
312 clickButton('AMP');
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800313 clickButton('UNDO');
Philipp Schradere11114f2023-04-15 17:04:25 -0700314 headerShouldBe('3990 Place ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800315 });
316
Philipp Schrader175a93c2023-02-19 13:13:40 -0800317 it('should: submit note scouting for multiple teams', () => {
318 // Navigate to Notes Page.
319 switchToTab('Notes');
320 headerShouldBe('Notes');
321
322 // Add first team.
323 setInputTo('#team_number_notes', '1234');
324 clickButton('Select');
325
326 // Add note and select keyword for first team.
327 cy.get('#team-key-1').should('have.text', '1234');
328 setInputTo('#text-input-1', 'Good Driving');
329 cy.get('#good_driving_0').click();
330
331 // Navigate to add team selection and add another team.
332 clickButton('Add team');
333 setInputTo('#team_number_notes', '1235');
Emily Markovacf893f42024-03-13 19:03:10 -0700334 setInputTo('#match_number_notes', 1);
335 setInputTo('#set_number_notes', 2);
336 setInputTo('#comp_level_notes', 'qm');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800337 clickButton('Select');
338
339 // Add note and select keyword for second team.
340 cy.get('#team-key-2').should('have.text', '1235');
341 setInputTo('#text-input-2', 'Bad Driving');
342 cy.get('#bad_driving_1').click();
343
344 // Submit Notes.
345 clickButton('Submit');
346 cy.get('#team_number_label').should('have.text', ' Team Number ');
347 });
348
349 it('should: switch note text boxes with keyboard shortcuts', () => {
350 // Navigate to Notes Page.
351 switchToTab('Notes');
352 headerShouldBe('Notes');
353
354 // Add first team.
355 setInputTo('#team_number_notes', '1234');
Emily Markovacf893f42024-03-13 19:03:10 -0700356 setInputTo('#match_number_notes', 1);
357 setInputTo('#set_number_notes', 2);
358 setInputTo('#comp_level_notes', 'qm');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800359 clickButton('Select');
360
361 // Add second team.
362 clickButton('Add team');
363 setInputTo('#team_number_notes', '1235');
Emily Markovacf893f42024-03-13 19:03:10 -0700364 setInputTo('#match_number_notes', 1);
365 setInputTo('#set_number_notes', 2);
366 setInputTo('#comp_level_notes', 'qm');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800367 clickButton('Select');
368
369 // Add third team.
370 clickButton('Add team');
371 setInputTo('#team_number_notes', '1236');
Emily Markovacf893f42024-03-13 19:03:10 -0700372 setInputTo('#match_number_notes', 1);
373 setInputTo('#set_number_notes', 2);
374 setInputTo('#comp_level_notes', 'qm');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800375 clickButton('Select');
376
377 for (let i = 1; i <= 3; i++) {
378 // Press Control + i
379 cy.get('body').type(`{ctrl}${i}`);
380
381 // Expect text input to be focused.
382 cy.focused().then(($element) => {
383 expect($element).to.have.id(`text-input-${i}`);
384 });
385 }
386 });
387
388 it('should: submit driver ranking', () => {
389 // Navigate to Driver Ranking Page.
390 switchToTab('Driver Ranking');
391 headerShouldBe('Driver Ranking');
392
393 // Input match and team numbers.
394 setInputTo('#match_number_selection', '11');
395 setInputTo('#team_input_0', '123');
396 setInputTo('#team_input_1', '456');
397 setInputTo('#team_input_2', '789');
398 clickButton('Select');
399
400 // Verify match and team key input.
401 cy.get('#match_number_heading').should('have.text', 'Match #11');
402 cy.get('#team_key_label_0').should('have.text', ' 123 ');
403 cy.get('#team_key_label_1').should('have.text', ' 456 ');
404 cy.get('#team_key_label_2').should('have.text', ' 789 ');
405
406 // Rank teams.
407 cy.get('#up_button_2').click();
408 cy.get('#down_button_0').click();
409
410 // Verify ranking change.
411 cy.get('#team_key_label_0').should('have.text', ' 789 ');
412 cy.get('#team_key_label_1').should('have.text', ' 123 ');
413 cy.get('#team_key_label_2').should('have.text', ' 456 ');
414
415 // Submit.
416 clickButton('Submit');
417 });
418});