@@ -27,6 +27,7 @@ import { CURLY_TEST_COMPONENT, GLIMMER_TEST_COMPONENT } from './components';
2727import { assertElementShape , assertEmberishElement } from './dom/assertions' ;
2828import { assertingElement , toInnerHTML } from './dom/simple-utils' ;
2929import { equalTokens , isServerMarker , normalizeSnapshot } from './snapshot' ;
30+ import { defineComponent } from './test-helpers/define' ;
3031
3132type Expand < T > = T extends infer O ? { [ K in keyof O ] : O [ K ] } : never ;
3233type Present < T > = Exclude < T , null | undefined > ;
@@ -430,6 +431,165 @@ export class RenderTest implements IRenderTest {
430431 inTransaction ( result . env , ( ) => destroy ( result ) ) ;
431432 }
432433
434+ private assertEachCompareResults (
435+ items : ( number | string | [ string | number , string | number ] ) [ ]
436+ ) {
437+ [ ...( this . element as unknown as HTMLElement ) . querySelectorAll ( '.test-item' ) ] . forEach (
438+ ( el , index ) => {
439+ let key = Array . isArray ( items [ index ] ) ? items [ index ] [ 0 ] : index ;
440+ let value = Array . isArray ( items [ index ] ) ? items [ index ] [ 1 ] : items [ index ] ;
441+
442+ QUnit . assert . equal ( el . textContent , `${ key } .${ value } ` ) ;
443+ }
444+ ) ;
445+ }
446+
447+ protected assertReactivity < T > (
448+ Klass : new ( ...args : any [ ] ) => { get value ( ) : T ; update : ( ) => void } ,
449+ shouldUpdate = true ,
450+ message ?: string
451+ ) {
452+ let instance : TestComponent | undefined ;
453+ let count = 0 ;
454+
455+ class TestComponent extends Klass {
456+ constructor ( ...args : unknown [ ] ) {
457+ super ( ...args ) ;
458+ // eslint-disable-next-line @typescript-eslint/no-this-alias
459+ instance = this ;
460+ }
461+
462+ override get value ( ) {
463+ count ++ ;
464+
465+ return super . value ;
466+ }
467+ }
468+
469+ if ( message ) {
470+ QUnit . assert . ok ( true , message ) ;
471+ }
472+
473+ let comp = defineComponent ( { } , `<div class="test">{{this.value}}</div>` , {
474+ strictMode : true ,
475+ definition : TestComponent ,
476+ } ) ;
477+
478+ this . renderComponent ( comp ) ;
479+
480+ QUnit . assert . equal ( count , 1 , `The count is 1` ) ;
481+
482+ if ( ! instance ) {
483+ throw new Error ( 'The instance is not defined' ) ;
484+ }
485+
486+ instance . update ( ) ;
487+
488+ this . rerender ( ) ;
489+
490+ QUnit . assert . equal (
491+ count ,
492+ shouldUpdate ? 2 : 1 ,
493+ shouldUpdate ? `The count is updated` : `The could should not update`
494+ ) ;
495+
496+ this . assertStableRerender ( ) ;
497+ }
498+
499+ protected assertEachInReactivity (
500+ Klass : new ( ...args : any [ ] ) => { collection : number [ ] ; update : ( ) => void }
501+ ) {
502+ let instance : TestComponent | undefined ;
503+
504+ class TestComponent extends Klass {
505+ constructor ( ...args : unknown [ ] ) {
506+ super ( ...args ) ;
507+ // eslint-disable-next-line
508+ instance = this ;
509+ }
510+ }
511+
512+ let comp = defineComponent (
513+ { } ,
514+ `
515+ <ul>
516+ {{#each-in this.collection as |lhs rhs|}}
517+ <li class="test-item">{{lhs}}.{{rhs}}</li>
518+ {{/each-in}}
519+ </ul>
520+ ` ,
521+ {
522+ strictMode : true ,
523+ definition : TestComponent ,
524+ }
525+ ) ;
526+
527+ this . renderComponent ( comp ) ;
528+
529+ if ( ! instance ) {
530+ throw new Error ( 'The instance is not defined' ) ;
531+ }
532+
533+ let { collection } = instance ;
534+
535+ this . assertEachCompareResults (
536+ Symbol . iterator in collection ? Array . from ( collection ) : Object . entries ( collection )
537+ ) ;
538+
539+ instance . update ( ) ;
540+
541+ this . rerender ( ) ;
542+
543+ this . assertEachCompareResults (
544+ Symbol . iterator in collection ? Array . from ( collection ) : Object . entries ( collection )
545+ ) ;
546+ }
547+
548+ protected assertEachReactivity (
549+ Klass : new ( ...args : any [ ] ) => { collection : number [ ] ; update : ( ) => void }
550+ ) {
551+ let instance : TestComponent | undefined ;
552+
553+ class TestComponent extends Klass {
554+ constructor ( ...args : any [ ] ) {
555+ super ( ...args ) ;
556+ // eslint-disable-next-line
557+ instance = this ;
558+ }
559+ }
560+
561+ let comp = defineComponent (
562+ { } ,
563+ `
564+ <ul>
565+ {{#each this.collection as |value index|}}
566+ <li class="test-item">{{index}}.{{value}}</li>
567+ {{/each}}
568+ </ul>
569+ ` ,
570+ {
571+ strictMode : true ,
572+ definition : TestComponent ,
573+ }
574+ ) ;
575+
576+ this . renderComponent ( comp ) ;
577+
578+ if ( ! instance ) {
579+ throw new Error ( 'The instance is not defined' ) ;
580+ }
581+
582+ this . assertEachCompareResults ( Array . from ( instance . collection ) . map ( ( v , i ) => [ i , v ] ) ) ;
583+
584+ instance . update ( ) ;
585+
586+ this . rerender ( ) ;
587+
588+ this . assertEachCompareResults ( Array . from ( instance . collection ) . map ( ( v , i ) => [ i , v ] ) ) ;
589+
590+ this . assertStableRerender ( ) ;
591+ }
592+
433593 protected set ( key : string , value : unknown ) : void {
434594 this . context [ key ] = value ;
435595 dirtyTagFor ( this . context , key ) ;
0 commit comments