blob: b1276d9c2864bf38f17056fc5fffcfbd00c18289 [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
87 // Pick and Place Cone in Auto.
88 clickButton('CONE');
89 clickButton('HIGH');
90
91 // Pick and Place Cube in Teleop.
92 clickButton('Start Teleop');
93 clickButton('CUBE');
94 clickButton('LOW');
95
96 // Robot dead and revive.
97 clickButton('DEAD');
98 clickButton('Revive');
99
100 // Endgame.
101 clickButton('Endgame');
102 cy.contains(/Docked & Engaged/).click();
103
104 clickButton('End Match');
105 headerShouldBe(teamNumber + ' Review and Submit ');
106 cy.get('#review_data li')
107 .eq(0)
108 .should('have.text', ' Started match at position 1 ');
109 cy.get('#review_data li').eq(1).should('have.text', ' Picked up kCone ');
110 cy.get('#review_data li')
111 .last()
112 .should(
113 'have.text',
114 ' Ended Match; docked: false, engaged: true, attempted to dock and engage: false '
115 );
116
117 clickButton('Submit');
118 headerShouldBe(teamNumber + ' Success ');
119}
120
Philipp Schrader175a93c2023-02-19 13:13:40 -0800121before(() => {
122 cy.visit('/');
123 disableAlerts();
124 cy.title().should('eq', 'FRC971 Scouting Application');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800125});
126
127beforeEach(() => {
128 cy.visit('/');
129 disableAlerts();
130});
131
132describe('Scouting app tests', () => {
133 it('should: show matches in chronological order.', () => {
134 headerShouldBe('Matches');
135 cy.get('.badge').eq(0).contains('Quals Match 1');
136 cy.get('.badge').eq(1).contains('Quals Match 2');
137 cy.get('.badge').eq(2).contains('Quals Match 3');
138 cy.get('.badge').eq(9).contains('Quals Match 10');
139 cy.get('.badge').eq(72).contains('Quarter Final 1 Match 1');
140 cy.get('.badge').eq(73).contains('Quarter Final 2 Match 1');
141 cy.get('.badge').eq(74).contains('Quarter Final 3 Match 1');
142 cy.get('.badge').eq(75).contains('Quarter Final 4 Match 1');
143 cy.get('.badge').eq(76).contains('Quarter Final 1 Match 2');
144 cy.get('.badge').eq(82).contains('Semi Final 1 Match 1');
145 cy.get('.badge').eq(83).contains('Semi Final 2 Match 1');
146 cy.get('.badge').eq(84).contains('Semi Final 1 Match 2');
147 cy.get('.badge').eq(85).contains('Semi Final 2 Match 2');
148 cy.get('.badge').eq(89).contains('Final 1 Match 3');
149 });
150
Philipp Schrader8702b782023-04-15 17:33:37 -0700151 it('should: prevent users from enter invalid match information.', () => {
152 switchToTab('Entry');
153 headerShouldBe(' Team Selection ');
154
155 setInputTo('#match_number', '1');
156 setInputTo('#team_number', '5254');
157 setInputTo('#set_number', '1');
158 cy.get('#comp_level').select('Qualifications');
159
160 cy.contains('button', 'Next').should('be.disabled');
161 });
162
Philipp Schradere1498852023-04-15 18:06:45 -0700163 it('should: allow users to scout non-existent matches when pre-scouting.', () => {
164 switchToTab('Entry');
165 headerShouldBe(' Team Selection ');
166 setInputTo('#team_number', '1');
167
168 // The default team information should be invalid.
169 cy.contains('button', 'Next').should('be.disabled');
170
171 // Click the checkmark to designate this as pre-scouting.
172 // We should now be able to continue scouting.
173 cy.get('#pre_scouting').click();
174 clickButton('Next');
175 headerShouldBe('1 Init ');
176 });
177
Philipp Schrader8702b782023-04-15 17:33:37 -0700178 it('should: let users enter match information manually.', () => {
Philipp Schrader75021f52023-04-09 21:14:13 -0700179 switchToTab('Entry');
Philipp Schrader2b334272023-04-11 21:27:36 -0700180 headerShouldBe(' Team Selection ');
Philipp Schrader75021f52023-04-09 21:14:13 -0700181
182 setInputTo('#match_number', '3');
183 setInputTo('#team_number', '5254');
184 setInputTo('#set_number', '2');
Philipp Schrader8702b782023-04-15 17:33:37 -0700185 cy.get('#comp_level').select('Semi Finals');
Philipp Schrader75021f52023-04-09 21:14:13 -0700186
187 clickButton('Next');
188
189 headerShouldBe('5254 Init ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800190 });
191
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800192 //TODO(FILIP): Verify last action when the last action header gets added.
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800193 it('should: be able to submit data scouting.', () => {
Filip Kujawac1ded372023-05-27 14:33:43 -0700194 submitDataScouting();
Philipp Schradere11114f2023-04-15 17:04:25 -0700195
196 // Now that the data is submitted, the button should be disabled.
197 switchToTab('Match List');
198 cy.get('button.match-item')
199 .eq(SEMI_FINAL_2_MATCH_3_TEAM_5254)
200 .should('be.disabled');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800201 });
202
Filip Kujawac1ded372023-05-27 14:33:43 -0700203 it('should: be able to delete data scouting entry', () => {
204 // Submit data to delete.
205 submitDataScouting(QUALS_MATCH_2_TEAM_4481, 4481);
206
207 switchToTab('View');
208
209 cy.get('[data-bs-toggle="dropdown"]').click();
210 cy.get('[id="stats_source_dropdown"]').click();
211
212 // Check that table contains data.
213 cy.get('table.table tbody td').should('contain', '4481');
214
215 // Find and click the delete button for the row containing team 4481.
216 cy.get('table.table tbody td')
217 .contains('4481')
218 .parent()
219 .find('[id^="delete_button_"]')
220 .click();
221 cy.on('window:confirm', () => true);
222
223 // Check that deleted data is not in table.
224 cy.get('table.table tbody').should('not.contain', '4481');
225 });
226
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800227 it('should: be able to return to correct screen with undo for pick and place.', () => {
Philipp Schradere11114f2023-04-15 17:04:25 -0700228 cy.get('button.match-item').eq(QUALS_MATCH_1_TEAM_3990).click();
Philipp Schrader2b334272023-04-11 21:27:36 -0700229
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800230 // Select Starting Position.
231 cy.get('[type="radio"]').first().check();
232 clickButton('Start Match');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800233
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800234 // Pick up cone.
235 clickButton('CONE');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800236
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800237 // Undo that pick up.
238 clickButton('UNDO');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800239
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800240 // User should be back on pickup screen.
Philipp Schradere11114f2023-04-15 17:04:25 -0700241 headerShouldBe('3990 Pickup ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800242
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800243 // Check the same thing but for undoing place.
244 clickButton('CUBE');
245 clickButton('MID');
246 clickButton('UNDO');
Philipp Schradere11114f2023-04-15 17:04:25 -0700247 headerShouldBe('3990 Place ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800248 });
249
Philipp Schrader175a93c2023-02-19 13:13:40 -0800250 it('should: submit note scouting for multiple teams', () => {
251 // Navigate to Notes Page.
252 switchToTab('Notes');
253 headerShouldBe('Notes');
254
255 // Add first team.
256 setInputTo('#team_number_notes', '1234');
257 clickButton('Select');
258
259 // Add note and select keyword for first team.
260 cy.get('#team-key-1').should('have.text', '1234');
261 setInputTo('#text-input-1', 'Good Driving');
262 cy.get('#good_driving_0').click();
263
264 // Navigate to add team selection and add another team.
265 clickButton('Add team');
266 setInputTo('#team_number_notes', '1235');
267 clickButton('Select');
268
269 // Add note and select keyword for second team.
270 cy.get('#team-key-2').should('have.text', '1235');
271 setInputTo('#text-input-2', 'Bad Driving');
272 cy.get('#bad_driving_1').click();
273
274 // Submit Notes.
275 clickButton('Submit');
276 cy.get('#team_number_label').should('have.text', ' Team Number ');
277 });
278
279 it('should: switch note text boxes with keyboard shortcuts', () => {
280 // Navigate to Notes Page.
281 switchToTab('Notes');
282 headerShouldBe('Notes');
283
284 // Add first team.
285 setInputTo('#team_number_notes', '1234');
286 clickButton('Select');
287
288 // Add second team.
289 clickButton('Add team');
290 setInputTo('#team_number_notes', '1235');
291 clickButton('Select');
292
293 // Add third team.
294 clickButton('Add team');
295 setInputTo('#team_number_notes', '1236');
296 clickButton('Select');
297
298 for (let i = 1; i <= 3; i++) {
299 // Press Control + i
300 cy.get('body').type(`{ctrl}${i}`);
301
302 // Expect text input to be focused.
303 cy.focused().then(($element) => {
304 expect($element).to.have.id(`text-input-${i}`);
305 });
306 }
307 });
308
309 it('should: submit driver ranking', () => {
310 // Navigate to Driver Ranking Page.
311 switchToTab('Driver Ranking');
312 headerShouldBe('Driver Ranking');
313
314 // Input match and team numbers.
315 setInputTo('#match_number_selection', '11');
316 setInputTo('#team_input_0', '123');
317 setInputTo('#team_input_1', '456');
318 setInputTo('#team_input_2', '789');
319 clickButton('Select');
320
321 // Verify match and team key input.
322 cy.get('#match_number_heading').should('have.text', 'Match #11');
323 cy.get('#team_key_label_0').should('have.text', ' 123 ');
324 cy.get('#team_key_label_1').should('have.text', ' 456 ');
325 cy.get('#team_key_label_2').should('have.text', ' 789 ');
326
327 // Rank teams.
328 cy.get('#up_button_2').click();
329 cy.get('#down_button_0').click();
330
331 // Verify ranking change.
332 cy.get('#team_key_label_0').should('have.text', ' 789 ');
333 cy.get('#team_key_label_1').should('have.text', ' 123 ');
334 cy.get('#team_key_label_2').should('have.text', ' 456 ');
335
336 // Submit.
337 clickButton('Submit');
338 });
339});