Philipp Schrader | e2e27ff | 2024-02-25 22:08:55 -0800 | [diff] [blame] | 1 | /// <reference types="cypress" /> |
| 2 | |
| 3 | // On the 3rd row of matches (index 2) click on the third team |
| 4 | // (index 2) which resolves to team 333 in quals match 3. |
| 5 | const QUALS_MATCH_3_TEAM_333 = 2 * 6 + 2; |
| 6 | |
| 7 | function disableAlerts() { |
| 8 | cy.get('#block_alerts').check({force: true}).should('be.checked'); |
| 9 | } |
| 10 | |
| 11 | function switchToTab(tabName) { |
| 12 | cy.contains('.nav-link', tabName).click(); |
| 13 | } |
| 14 | |
| 15 | function headerShouldBe(text) { |
| 16 | cy.get('.header').should('have.text', text); |
| 17 | } |
| 18 | |
| 19 | function clickButton(buttonName) { |
| 20 | cy.contains('button', buttonName).click(); |
| 21 | } |
| 22 | |
| 23 | // Wrapper around cy.exec() because it truncates the output of the subprocess |
| 24 | // if it fails. This is a work around to manually print the full error on the |
| 25 | // console if a failure happends. |
| 26 | function exec(command) { |
| 27 | cy.exec(command, {failOnNonZeroExit: false}).then((result) => { |
| 28 | if (result.code) { |
| 29 | throw new Error(`Execution of "${command}" failed |
| 30 | Exit code: ${result.code} |
| 31 | Stdout:\n${result.stdout} |
| 32 | Stderr:\n${result.stderr}`); |
| 33 | } |
| 34 | }); |
| 35 | } |
| 36 | |
| 37 | // Prepares data entry so that we _could_ hit Submit. |
| 38 | // |
| 39 | // Options: |
| 40 | // matchButtonKey: The index into the big matchlist table that we want to |
| 41 | // click on to start the data entry. |
| 42 | // teamNumber: The team number that matches the button that we click on as |
| 43 | // specified by `matchButtonKey`. |
| 44 | // |
| 45 | // TODO(phil): Deduplicate with scouting_test.cy.js. |
| 46 | function prepareDataScouting(options) { |
| 47 | const {matchButtonKey = SEMI_FINAL_2_MATCH_3_TEAM_5254, teamNumber = 5254} = |
| 48 | options; |
| 49 | |
| 50 | // Click on a random team in the Match list. The exact details here are not |
| 51 | // important, but we need to know what they are. This could as well be any |
| 52 | // other team from any other match. |
| 53 | cy.get('button.match-item').eq(matchButtonKey).click(); |
| 54 | |
| 55 | // Select Starting Position. |
| 56 | headerShouldBe(teamNumber + ' Init '); |
| 57 | cy.get('[type="radio"]').first().check(); |
| 58 | clickButton('Start Match'); |
| 59 | |
| 60 | // Pick and Place Note in Auto. |
| 61 | clickButton('NOTE'); |
| 62 | clickButton('AMP'); |
| 63 | |
| 64 | // Pick and Place Cube in Teleop. |
| 65 | clickButton('Start Teleop'); |
| 66 | clickButton('NOTE'); |
| 67 | clickButton('AMP AMPLIFIED'); |
| 68 | |
| 69 | // Generate some extra actions so that we are guaranteed to have at least 2 |
| 70 | // QR codes. |
| 71 | for (let i = 0; i < 5; i++) { |
| 72 | clickButton('NOTE'); |
| 73 | clickButton('AMP'); |
| 74 | } |
| 75 | |
| 76 | // Robot dead and revive. |
| 77 | clickButton('DEAD'); |
| 78 | clickButton('Revive'); |
| 79 | |
| 80 | // Endgame. |
| 81 | clickButton('Endgame'); |
| 82 | cy.contains(/Harmony/).click(); |
| 83 | |
| 84 | clickButton('End Match'); |
| 85 | headerShouldBe(teamNumber + ' Review and Submit '); |
| 86 | cy.get('#review_data li') |
| 87 | .eq(0) |
| 88 | .should('have.text', ' Started match at position 1 '); |
Philipp Schrader | 3d7dedc | 2024-03-16 16:27:25 -0700 | [diff] [blame] | 89 | cy.get('#review_data li').eq(1).should('have.text', ' Picked up Note '); |
Philipp Schrader | e2e27ff | 2024-02-25 22:08:55 -0800 | [diff] [blame] | 90 | cy.get('#review_data li') |
| 91 | .last() |
| 92 | .should( |
| 93 | 'have.text', |
| 94 | ' Ended Match; stageType: kHARMONY, trapNote: false, spotlight: false ' |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | before(() => { |
| 99 | cy.visit('/'); |
| 100 | disableAlerts(); |
| 101 | cy.title().should('eq', 'FRC971 Scouting Application'); |
| 102 | }); |
| 103 | |
| 104 | beforeEach(() => { |
| 105 | cy.visit('/'); |
| 106 | disableAlerts(); |
| 107 | }); |
| 108 | |
| 109 | describe('Scouting app tests', () => { |
| 110 | // This test collects some scouting data and then generates the corresponding |
| 111 | // QR codes. The test takes screenshots of those QR codes. The QR codes get |
| 112 | // turned into a little video file for the browser to use as a fake camera |
| 113 | // input. The test then switches to the Scan tab to scan the QR codes from |
| 114 | // the "camera". We then make sure that the data gets submitted. |
| 115 | it('should: be able to generate and scan QR codes.', () => { |
| 116 | prepareDataScouting({ |
| 117 | matchButtonKey: QUALS_MATCH_3_TEAM_333, |
| 118 | teamNumber: 333, |
| 119 | }); |
| 120 | clickButton('Create QR Code'); |
| 121 | headerShouldBe('333 QR Code '); |
| 122 | |
| 123 | cy.get('#qr_code_piece_size').select('150'); |
| 124 | |
| 125 | // Go into a mobile-phone view so that we can guarantee that the QR code is |
| 126 | // visible. |
| 127 | cy.viewport(400, 660); |
| 128 | |
| 129 | cy.get('.qrcode-buttons > li > a') |
| 130 | .should('have.length.at.least', 4) |
| 131 | .each(($button, index, $buttons) => { |
| 132 | if (index == 0 || index + 1 == $buttons.length) { |
| 133 | // Skip the "Previous" and "Next" buttons. |
| 134 | return; |
| 135 | } |
| 136 | // Click on the button to switch to that particular QR code. |
| 137 | // We use force:true here because without bootstrap (inside the |
| 138 | // sandbox) the buttons overlap one another a bit. |
| 139 | cy.wrap($button).click({force: true}); |
| 140 | cy.get('div.qrcode').screenshot(`qrcode_${index}_screenshot`); |
| 141 | }); |
| 142 | |
| 143 | exec('./testing/camera_simulator/camera_simulator_/camera_simulator'); |
| 144 | |
| 145 | switchToTab('Scan'); |
| 146 | |
| 147 | // Since we cannot reliably predict how long it will take to scan all the |
| 148 | // QR codes, we use a really long timeout here. |
| 149 | cy.get('.progress_message', {timeout: 80000}).should('contain', 'Success!'); |
| 150 | |
| 151 | // Now that the data is submitted, the button should be disabled. |
| 152 | switchToTab('Match List'); |
| 153 | cy.get('button.match-item') |
| 154 | .eq(QUALS_MATCH_3_TEAM_333) |
| 155 | .should('be.disabled'); |
| 156 | }); |
| 157 | }); |