Search code examples
angularivy

Trigger Angular Ivy Change detection with Cypress


I have the following Cypress test:

 ...

 describe('Form filling works properly, () => {
    it.only('should enable save button with correct form', () => {
      cy.get('input[name=notiName]').type('Test data for notiName, { force: true });
      cy.get('input[name=notiEnMessageName]').type('Test data for EnMessageName', { force: true 
    });

      cy.get('.navigationContainer [data-cy=btn-save]').should('be.enabled');
    });
  });

This works just fine.

But I have a third input value on the form, which is a complex data picker, and I would like to handle setting up value for it with its formControl instead of manually programming all the clicks required. Let's call the formControl specialInputFormcontrol˙for now.

So I do this:

 describe('New notification works properly', () => {
    it.only('should enable save button with correct form', () => {
      cy.get('input[name=notiName]').type('Test data for notiName, { force: true });
      cy.get('input[name=notiEnMessageName]').type('Test data for EnMessageName', { force: true 

      let angular;
      cy.window()
        .then((win) => angular = win.ng)
        .then(() => cy.document())
        .then((doc) => {
          cy.log('Angular component captured');
          const componentInstance = angular
            .getComponent(doc.querySelector('my-component-name'));

          componentInstance.specialInputFormcontrol.setValue("special value");

           // change detection here?
        });

      cy.get('.navigationContainer [data-cy=btn-save]').should('be.enabled');
    });
  });

My problem is, that although the value get updated, due to Angular's engine I still need to force a change detection tick, to apply the cahnges.

I have tried to place the following codes in place of the // change detection here? part as attempts at this:

  angular.applyChanges(componentInstance)

This resets the whole page.

  angular.applyChanges(angular.getComponent($0);

$0 is not defined.

   angular.probe(getAllAngularRootElements()[0]).injector.get(ng.coreTokens.ApplicationRef).tick()

angular.probe won't work in Ivy. (after angular 9)

   componentInstance.injector.get(angular.coreTokens.ApplicationRef).tick();

"TypeError: cannot read property 'get' of undefined".

Update:

          ɵdetectChanges(componentInstance);

As ChrisY pointed it out, after importing it I was able to call this, but got TypeError: Cannot read property 'length' of null

So as you can see, I looked up a few ideas, and none of the worked :(


Solution

  • Found the solution - one should use the angular debug hook to apply changes directly on the component reference like this:

    describe('New notification works properly', () => {
        it.only('should enable save button with correct form', () => {
          cy.get('input[name=notiName]').type('Test data for notiName, { force: true });
          cy.get('input[name=notiEnMessageName]').type('Test data for EnMessageName', { force: true 
    
          let angular;
          cy.window()
            .then((win) => angular = win.ng)
            .then(() => cy.document())
            .then((doc) => {
              cy.log('Angular component captured');
              const componentInstance = angular
                .getComponent(doc.querySelector('my-component-name'));
    
              componentInstance.specialInputFormcontrol.setValue("special value");
    
              // Change detection trigger:
              angular.applyChanges(componentInstance)
    
            });
    
          cy.get('.navigationContainer [data-cy=btn-save]').should('be.enabled');
        });
      });