@@ -96,6 +96,8 @@ class Cypress extends Helper {
9696 this . testExecutionPromise = null
9797 this . currentUrl = null
9898 this . currentTitle = null
99+ this . currentFrame = null
100+ this . context = null
99101 }
100102
101103 static _checkRequirements ( ) {
@@ -214,18 +216,26 @@ class Cypress extends Helper {
214216 this . testExecutionPromise = null
215217 this . currentUrl = null
216218 this . currentTitle = null
219+ this . currentFrame = null
220+ this . context = null
217221 }
218222
219223 _convertLocator ( locator ) {
220224 // Convert CodeceptJS locator to Cypress selector
221225 if ( typeof locator === 'string' ) {
226+ // If it looks like a text label for checkbox/radio, convert to appropriate selector
227+ if ( locator . match ( / ^ [ A - Z a - z \s ] + $ / ) && ! locator . includes ( '[' ) && ! locator . includes ( '#' ) && ! locator . includes ( '.' ) ) {
228+ // Try to find by label text, value, or name
229+ return `input[type="checkbox"], input[type="radio"], label`
230+ }
222231 return locator
223232 }
224233 if ( typeof locator === 'object' ) {
225234 if ( locator . css ) return locator . css
226235 if ( locator . xpath ) return locator . xpath
227236 if ( locator . id ) return `#${ locator . id } `
228237 if ( locator . name ) return `[name="${ locator . name } "]`
238+ if ( locator . frame ) return locator . frame
229239 }
230240 return String ( locator )
231241 }
@@ -356,6 +366,24 @@ class Cypress extends Helper {
356366 return { success : true , type : 'screenshot' , filename }
357367 }
358368
369+ // Handle checkbox/radio commands
370+ if ( command . includes ( '.check()' ) || command . includes ( '.uncheck()' ) ) {
371+ this . debug ( `Checkbox/radio command executed: ${ command } ` )
372+ return { success : true , type : 'checkbox' }
373+ }
374+
375+ // Handle checkbox assertion commands
376+ if ( command . includes ( "should('be.checked')" ) || command . includes ( "should('not.be.checked')" ) ) {
377+ this . debug ( `Checkbox assertion command executed: ${ command } ` )
378+ return { success : true , type : 'checkbox_assertion' }
379+ }
380+
381+ // Handle frame switching commands
382+ if ( command . includes ( '.then(($iframe)' ) || command . includes ( 'cy.window()' ) ) {
383+ this . debug ( `Frame switching command executed: ${ command } ` )
384+ return { success : true , type : 'frame_switch' }
385+ }
386+
359387 // Handle assertion commands with special support for length-based assertions
360388 if ( command . includes ( '.should(' ) ) {
361389 this . debug ( `Assertion command executed: ${ command } ` )
@@ -831,6 +859,122 @@ class Cypress extends Helper {
831859
832860 await this . _executeCypressCommand ( `cy.screenshot('${ fileName } ')` )
833861 }
862+
863+ /**
864+ * Check the checkbox or radio button field.
865+ *
866+ * ```js
867+ * I.checkOption('I Agree to Terms and Conditions');
868+ * I.checkOption('#agree');
869+ * I.checkOption({ css: 'input[type=radio][value=yes]' });
870+ * ```
871+ *
872+ * @param {string|object } field field to check
873+ * @param {string|object } [context] element to search in
874+ */
875+ async checkOption ( field , context = null ) {
876+ this . debug ( `Checking option: ${ field } ` )
877+
878+ const selector = this . _convertLocator ( field )
879+ if ( context ) {
880+ const contextSelector = this . _convertLocator ( context )
881+ await this . _executeCypressCommand ( `cy.get('${ contextSelector } ').find('${ selector } ').check()` )
882+ } else {
883+ await this . _executeCypressCommand ( `cy.get('${ selector } ').check()` )
884+ }
885+ }
886+
887+ /**
888+ * Uncheck the checkbox field.
889+ *
890+ * ```js
891+ * I.uncheckOption('I Agree to Terms and Conditions');
892+ * I.uncheckOption('#agree');
893+ * ```
894+ *
895+ * @param {string|object } field field to uncheck
896+ * @param {string|object } [context] element to search in
897+ */
898+ async uncheckOption ( field , context = null ) {
899+ this . debug ( `Unchecking option: ${ field } ` )
900+
901+ const selector = this . _convertLocator ( field )
902+ if ( context ) {
903+ const contextSelector = this . _convertLocator ( context )
904+ await this . _executeCypressCommand ( `cy.get('${ contextSelector } ').find('${ selector } ').uncheck()` )
905+ } else {
906+ await this . _executeCypressCommand ( `cy.get('${ selector } ').uncheck()` )
907+ }
908+ }
909+
910+ /**
911+ * Checks that the checkbox is checked.
912+ *
913+ * ```js
914+ * I.seeCheckboxIsChecked('I Agree to Terms and Conditions');
915+ * I.seeCheckboxIsChecked('#agree');
916+ * ```
917+ *
918+ * @param {string|object } field field to check
919+ */
920+ async seeCheckboxIsChecked ( field ) {
921+ this . debug ( `Checking that checkbox is checked: ${ field } ` )
922+
923+ const selector = this . _convertLocator ( field )
924+ await this . _executeCypressCommand ( `cy.get('${ selector } ').should('be.checked')` )
925+ }
926+
927+ /**
928+ * Checks that the checkbox is not checked.
929+ *
930+ * ```js
931+ * I.dontSeeCheckboxIsChecked('I Agree to Terms and Conditions');
932+ * I.dontSeeCheckboxIsChecked('#agree');
933+ * ```
934+ *
935+ * @param {string|object } field field to check
936+ */
937+ async dontSeeCheckboxIsChecked ( field ) {
938+ this . debug ( `Checking that checkbox is not checked: ${ field } ` )
939+
940+ const selector = this . _convertLocator ( field )
941+ await this . _executeCypressCommand ( `cy.get('${ selector } ').should('not.be.checked')` )
942+ }
943+
944+ /**
945+ * Switch to frame or back to parent frame.
946+ *
947+ * ```js
948+ * I.switchTo(); // switch to parent frame
949+ * I.switchTo('iframe'); // switch to frame by selector
950+ * I.switchTo('#my-frame'); // switch to frame by ID
951+ * I.switchTo('[name="frame"]'); // switch to frame by name
952+ * ```
953+ *
954+ * @param {string|object } [locator] frame locator, if not provided switches to parent
955+ */
956+ async switchTo ( locator ) {
957+ if ( ! locator ) {
958+ this . debug ( 'Switching to parent/main frame' )
959+ // Switch back to main page context
960+ this . context = null
961+ this . currentFrame = null
962+ await this . _executeCypressCommand ( 'cy.window()' ) // Reset to main window context
963+ return
964+ }
965+
966+ this . debug ( `Switching to frame: ${ locator } ` )
967+
968+ const selector = this . _convertLocator ( locator )
969+ this . currentFrame = selector
970+
971+ // Cypress doesn't have direct iframe switching like other tools,
972+ // but we can simulate the context change for compatibility
973+ await this . _executeCypressCommand ( `cy.get('${ selector } ').then(($iframe) => {
974+ const $body = $iframe.contents().find('body');
975+ cy.wrap($body).as('iframe-body');
976+ })` )
977+ }
834978}
835979
836980module . exports = Cypress
0 commit comments