@@ -100,47 +100,9 @@ export default function (Commands, Cypress, cy, state) {
100100
101101 cy . once ( 'command:enqueued' , enqueuedCommand )
102102
103- // this code helps juggle subjects forward
104- // the same way that promises work
105- const current = state ( 'current' )
106- const next = current . get ( 'next' )
107-
108- // TODO: this code may no longer be necessary
109- // if the next command is chained to us then when it eventually
110- // runs we need to reset the subject to be the return value of the
111- // previous command so the subject is continuously juggled forward
112- if ( next && next . get ( 'chainerId' ) === current . get ( 'chainerId' ) ) {
113- const checkSubject = ( newSubject , args ) => {
114- if ( state ( 'current' ) !== next ) {
115- return
116- }
117-
118- // get whatever the previous commands return
119- // value is. this likely does not match the 'var current'
120- // command in the case of nested cy commands
121- const s = next . get ( 'prev' ) . get ( 'subject' )
122-
123- // find the new subject and splice it out
124- // with our existing subject
125- const index = _ . indexOf ( args , newSubject )
126-
127- if ( index > - 1 ) {
128- args . splice ( index , 1 , s )
129- }
130-
131- return cy . removeListener ( 'next:subject:prepared' , checkSubject )
132- }
133-
134- cy . on ( 'next:subject:prepared' , checkSubject )
135- }
136-
137103 const getRet = ( ) => {
138104 let ret = fn . apply ( ctx , args )
139105
140- if ( cy . isCy ( ret ) ) {
141- ret = undefined
142- }
143-
144106 if ( ret && invokedCyCommand && ! ret . then ) {
145107 $errUtils . throwErrByPath ( 'then.callback_mixes_sync_and_async' , {
146108 onFail : options . _log ,
@@ -161,6 +123,11 @@ export default function (Commands, Cypress, cy, state) {
161123 return subject
162124 }
163125
126+ // If the user callback returned a non-null value, we break cypress' subject chaining
127+ // logic, so that we can use this subject as-is rather than the subject generated by
128+ // any chainers inside the callback (if any exist).
129+ cy . breakSubjectLinksToCurrentChainer ( )
130+
164131 return ret
165132 } ) . catch ( Promise . TimeoutError , ( ) => {
166133 return $errUtils . throwErrByPath ( 'invoke_its.timed_out' , {
@@ -498,54 +465,16 @@ export default function (Commands, Cypress, cy, state) {
498465 $errUtils . throwErrByPath ( 'each.invalid_argument' )
499466 }
500467
501- const nonArray = ( ) => {
468+ if ( subject ?. length === undefined ) {
502469 return $errUtils . throwErrByPath ( 'each.non_array' , {
503470 args : { subject : $utils . stringify ( subject ) } ,
504471 } )
505472 }
506473
507- try {
508- if ( ! ( 'length' in subject ) ) {
509- nonArray ( )
510- }
511- } catch ( e ) {
512- nonArray ( )
513- }
514-
515474 if ( subject . length === 0 ) {
516475 return subject
517476 }
518477
519- // if we have a next command then we need to
520- // slice in this existing subject as its subject
521- // due to the way we queue promises
522- const next = state ( 'current' ) . get ( 'next' )
523-
524- if ( next ) {
525- const checkSubject = ( newSubject , args , firstCall ) => {
526- if ( state ( 'current' ) !== next ) {
527- return
528- }
529-
530- // https://github.com/cypress-io/cypress/issues/4921
531- // When dual commands like contains() is used as the firstCall (cy.contains() style),
532- // we should not prepend subject.
533- if ( ! firstCall ) {
534- // find the new subject and splice it out
535- // with our existing subject
536- const index = _ . indexOf ( args , newSubject )
537-
538- if ( index > - 1 ) {
539- args . splice ( index , 1 , subject )
540- }
541- }
542-
543- return cy . removeListener ( 'next:subject:prepared' , checkSubject )
544- }
545-
546- cy . on ( 'next:subject:prepared' , checkSubject )
547- }
548-
549478 let endEarly = false
550479
551480 const yieldItem = ( el , index ) => {
@@ -573,11 +502,16 @@ export default function (Commands, Cypress, cy, state) {
573502
574503 // generate a real array since bluebird is finicky and
575504 // doesnt want an 'array-like' structure like jquery instances
576- // need to take into account regular arrays here by first checking
577- // if its an array instance
578505 return Promise
579506 . each ( _ . toArray ( subject ) , yieldItem )
580- . return ( subject )
507+ . then ( ( ) => {
508+ // cy.each does *not* want to use any subjects that the user's callback generated - therefore we break
509+ // cypress' subject chaining logic, which by default would override this with any subjects generated by
510+ // the callback function.
511+ cy . breakSubjectLinksToCurrentChainer ( )
512+
513+ return subject
514+ } )
581515 } ,
582516 } )
583517
0 commit comments