blob: e4dcfc7fd27283ae0e4f112a3c25c1bdd4347c17 [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
Philipp Schrader175a93c2023-02-19 13:13:40 -080011function disableAlerts() {
12 cy.get('#block_alerts').check({force: true}).should('be.checked');
13}
14
15function switchToTab(tabName) {
16 cy.contains('.nav-link', tabName).click();
17}
18
19function headerShouldBe(text) {
20 cy.get('.header').should('have.text', text);
21}
22
23function clickButton(buttonName) {
24 cy.contains('button', buttonName).click();
25}
26
27function setInputTo(fieldSelector, value) {
28 cy.get(fieldSelector).type('{selectAll}' + value);
29}
30
31// Moves the nth slider left or right. A positive "adjustBy" value moves the
32// slider to the right. A negative value moves the slider to the left.
33//
34// negative/left <--- 0 ---> positive/right
35function adjustNthSliderBy(n, adjustBy) {
36 let element = cy.get('input[type=range]').eq(n);
37 element.scrollIntoView();
38 element.invoke('val').then((currentValue) => {
39 // We need to query for the slider here again because `invoke('val')` above
40 // somehow invalidates further calls to `val`.
41 cy.get('input[type=range]')
42 .eq(n)
43 .invoke('val', currentValue + adjustBy)
44 .trigger('change');
45 });
46}
47
48// Asserts that the field on the "Submit and Review" screen has a specific
49// value.
50function expectReviewFieldToBe(fieldName, expectedValue) {
51 expectNthReviewFieldToBe(fieldName, 0, expectedValue);
52}
53
54// Asserts that the n'th instance of a field on the "Submit and Review"
55// screen has a specific value.
56function expectNthReviewFieldToBe(fieldName, n, expectedValue) {
57 getNthReviewField(fieldName, n).should(
58 'have.text',
59 `${fieldName}: ${expectedValue}`
60 );
61}
62
63function getNthReviewField(fieldName, n) {
64 let element = cy.get('li').filter(`:contains("${fieldName}: ")`).eq(n);
65 element.scrollIntoView();
66 return element;
67}
68
69before(() => {
70 cy.visit('/');
71 disableAlerts();
72 cy.title().should('eq', 'FRC971 Scouting Application');
Philipp Schrader175a93c2023-02-19 13:13:40 -080073});
74
75beforeEach(() => {
76 cy.visit('/');
77 disableAlerts();
78});
79
80describe('Scouting app tests', () => {
81 it('should: show matches in chronological order.', () => {
82 headerShouldBe('Matches');
83 cy.get('.badge').eq(0).contains('Quals Match 1');
84 cy.get('.badge').eq(1).contains('Quals Match 2');
85 cy.get('.badge').eq(2).contains('Quals Match 3');
86 cy.get('.badge').eq(9).contains('Quals Match 10');
87 cy.get('.badge').eq(72).contains('Quarter Final 1 Match 1');
88 cy.get('.badge').eq(73).contains('Quarter Final 2 Match 1');
89 cy.get('.badge').eq(74).contains('Quarter Final 3 Match 1');
90 cy.get('.badge').eq(75).contains('Quarter Final 4 Match 1');
91 cy.get('.badge').eq(76).contains('Quarter Final 1 Match 2');
92 cy.get('.badge').eq(82).contains('Semi Final 1 Match 1');
93 cy.get('.badge').eq(83).contains('Semi Final 2 Match 1');
94 cy.get('.badge').eq(84).contains('Semi Final 1 Match 2');
95 cy.get('.badge').eq(85).contains('Semi Final 2 Match 2');
96 cy.get('.badge').eq(89).contains('Final 1 Match 3');
97 });
98
Philipp Schrader8702b782023-04-15 17:33:37 -070099 it('should: prevent users from enter invalid match information.', () => {
100 switchToTab('Entry');
101 headerShouldBe(' Team Selection ');
102
103 setInputTo('#match_number', '1');
104 setInputTo('#team_number', '5254');
105 setInputTo('#set_number', '1');
106 cy.get('#comp_level').select('Qualifications');
107
108 cy.contains('button', 'Next').should('be.disabled');
109 });
110
Philipp Schradere1498852023-04-15 18:06:45 -0700111 it('should: allow users to scout non-existent matches when pre-scouting.', () => {
112 switchToTab('Entry');
113 headerShouldBe(' Team Selection ');
114 setInputTo('#team_number', '1');
115
116 // The default team information should be invalid.
117 cy.contains('button', 'Next').should('be.disabled');
118
119 // Click the checkmark to designate this as pre-scouting.
120 // We should now be able to continue scouting.
121 cy.get('#pre_scouting').click();
122 clickButton('Next');
123 headerShouldBe('1 Init ');
124 });
125
Philipp Schrader8702b782023-04-15 17:33:37 -0700126 it('should: let users enter match information manually.', () => {
Philipp Schrader75021f52023-04-09 21:14:13 -0700127 switchToTab('Entry');
Philipp Schrader2b334272023-04-11 21:27:36 -0700128 headerShouldBe(' Team Selection ');
Philipp Schrader75021f52023-04-09 21:14:13 -0700129
130 setInputTo('#match_number', '3');
131 setInputTo('#team_number', '5254');
132 setInputTo('#set_number', '2');
Philipp Schrader8702b782023-04-15 17:33:37 -0700133 cy.get('#comp_level').select('Semi Finals');
Philipp Schrader75021f52023-04-09 21:14:13 -0700134
135 clickButton('Next');
136
137 headerShouldBe('5254 Init ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800138 });
139
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800140 //TODO(FILIP): Verify last action when the last action header gets added.
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800141 it('should: be able to submit data scouting.', () => {
Philipp Schradere11114f2023-04-15 17:04:25 -0700142 // Click on a random team in the Match list. The exact details here are not
143 // important, but we need to know what they are. This could as well be any
144 // other team from any other match.
145 cy.get('button.match-item').eq(SEMI_FINAL_2_MATCH_3_TEAM_5254).click();
Philipp Schrader2b334272023-04-11 21:27:36 -0700146
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800147 // Select Starting Position.
Philipp Schrader2b334272023-04-11 21:27:36 -0700148 headerShouldBe('5254 Init ');
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800149 cy.get('[type="radio"]').first().check();
150 clickButton('Start Match');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800151
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800152 // Pick and Place Cone in Auto.
153 clickButton('CONE');
154 clickButton('HIGH');
155
156 // Pick and Place Cube in Teleop.
157 clickButton('Start Teleop');
158 clickButton('CUBE');
159 clickButton('LOW');
160
161 // Robot dead and revive.
162 clickButton('DEAD');
163 clickButton('Revive');
164
Philipp Schradere11114f2023-04-15 17:04:25 -0700165 // Endgame.
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800166 clickButton('Endgame');
167 cy.get('[type="checkbox"]').check();
168
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800169 clickButton('End Match');
Philipp Schrader2b334272023-04-11 21:27:36 -0700170 headerShouldBe('5254 Review and Submit ');
Emily Markovaf4b06a22023-05-10 17:44:09 -0700171 cy.get('#review_data li')
172 .eq(0)
173 .should('have.text', ' Started match at position 1 ');
174 cy.get('#review_data li').eq(1).should('have.text', ' Picked up kCone ');
175 cy.get('#review_data li')
176 .last()
177 .should(
178 'have.text',
179 ' Ended Match; docked: true, engaged: true, attempted to dock and engage: true '
180 );
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800181
182 clickButton('Submit');
Philipp Schrader2b334272023-04-11 21:27:36 -0700183 headerShouldBe('5254 Success ');
Philipp Schradere11114f2023-04-15 17:04:25 -0700184
185 // Now that the data is submitted, the button should be disabled.
186 switchToTab('Match List');
187 cy.get('button.match-item')
188 .eq(SEMI_FINAL_2_MATCH_3_TEAM_5254)
189 .should('be.disabled');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800190 });
191
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800192 it('should: be able to return to correct screen with undo for pick and place.', () => {
Philipp Schradere11114f2023-04-15 17:04:25 -0700193 cy.get('button.match-item').eq(QUALS_MATCH_1_TEAM_3990).click();
Philipp Schrader2b334272023-04-11 21:27:36 -0700194
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800195 // Select Starting Position.
196 cy.get('[type="radio"]').first().check();
197 clickButton('Start Match');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800198
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800199 // Pick up cone.
200 clickButton('CONE');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800201
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800202 // Undo that pick up.
203 clickButton('UNDO');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800204
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800205 // User should be back on pickup screen.
Philipp Schradere11114f2023-04-15 17:04:25 -0700206 headerShouldBe('3990 Pickup ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800207
Filip Kujawa2dc9aa62023-03-04 11:45:01 -0800208 // Check the same thing but for undoing place.
209 clickButton('CUBE');
210 clickButton('MID');
211 clickButton('UNDO');
Philipp Schradere11114f2023-04-15 17:04:25 -0700212 headerShouldBe('3990 Place ');
Philipp Schrader175a93c2023-02-19 13:13:40 -0800213 });
214
Philipp Schrader175a93c2023-02-19 13:13:40 -0800215 it('should: submit note scouting for multiple teams', () => {
216 // Navigate to Notes Page.
217 switchToTab('Notes');
218 headerShouldBe('Notes');
219
220 // Add first team.
221 setInputTo('#team_number_notes', '1234');
222 clickButton('Select');
223
224 // Add note and select keyword for first team.
225 cy.get('#team-key-1').should('have.text', '1234');
226 setInputTo('#text-input-1', 'Good Driving');
227 cy.get('#good_driving_0').click();
228
229 // Navigate to add team selection and add another team.
230 clickButton('Add team');
231 setInputTo('#team_number_notes', '1235');
232 clickButton('Select');
233
234 // Add note and select keyword for second team.
235 cy.get('#team-key-2').should('have.text', '1235');
236 setInputTo('#text-input-2', 'Bad Driving');
237 cy.get('#bad_driving_1').click();
238
239 // Submit Notes.
240 clickButton('Submit');
241 cy.get('#team_number_label').should('have.text', ' Team Number ');
242 });
243
244 it('should: switch note text boxes with keyboard shortcuts', () => {
245 // Navigate to Notes Page.
246 switchToTab('Notes');
247 headerShouldBe('Notes');
248
249 // Add first team.
250 setInputTo('#team_number_notes', '1234');
251 clickButton('Select');
252
253 // Add second team.
254 clickButton('Add team');
255 setInputTo('#team_number_notes', '1235');
256 clickButton('Select');
257
258 // Add third team.
259 clickButton('Add team');
260 setInputTo('#team_number_notes', '1236');
261 clickButton('Select');
262
263 for (let i = 1; i <= 3; i++) {
264 // Press Control + i
265 cy.get('body').type(`{ctrl}${i}`);
266
267 // Expect text input to be focused.
268 cy.focused().then(($element) => {
269 expect($element).to.have.id(`text-input-${i}`);
270 });
271 }
272 });
273
274 it('should: submit driver ranking', () => {
275 // Navigate to Driver Ranking Page.
276 switchToTab('Driver Ranking');
277 headerShouldBe('Driver Ranking');
278
279 // Input match and team numbers.
280 setInputTo('#match_number_selection', '11');
281 setInputTo('#team_input_0', '123');
282 setInputTo('#team_input_1', '456');
283 setInputTo('#team_input_2', '789');
284 clickButton('Select');
285
286 // Verify match and team key input.
287 cy.get('#match_number_heading').should('have.text', 'Match #11');
288 cy.get('#team_key_label_0').should('have.text', ' 123 ');
289 cy.get('#team_key_label_1').should('have.text', ' 456 ');
290 cy.get('#team_key_label_2').should('have.text', ' 789 ');
291
292 // Rank teams.
293 cy.get('#up_button_2').click();
294 cy.get('#down_button_0').click();
295
296 // Verify ranking change.
297 cy.get('#team_key_label_0').should('have.text', ' 789 ');
298 cy.get('#team_key_label_1').should('have.text', ' 123 ');
299 cy.get('#team_key_label_2').should('have.text', ' 456 ');
300
301 // Submit.
302 clickButton('Submit');
303 });
304});