<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged cyress</title>
<link>https://coderlegion.com/tag/cyress</link>
<description>Powered by Question2Answer</description>
<item>
<title>A Complete Guide to Angular Component Testing with Cypress</title>
<link>https://coderlegion.com/13405/a-complete-guide-to-angular-component-testing-with-cypress</link>
<description>&lt;p&gt;Angular's latest versions have introduced exciting features like signals, computed, and enhanced reactivity. Paired with Cypress Component Testing, developers now have a powerful toolkit to write fast, realistic, and robust tests. This post dives deep into Angular component testing using Cypress, including how to test components that use signals, observables, and mock services with confidence.&lt;/p&gt;
&lt;h4 id=&quot;-why-cypress-for-angular-component-testing-&quot;&gt;✨ Why Cypress for Angular Component Testing?&lt;/h4&gt;
&lt;p&gt;Cypress isn't just for end-to-end tests. With Cypress Component Testing, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Render Angular components in isolation&lt;/li&gt;
&lt;li&gt;Interact with them as a user would&lt;/li&gt;
&lt;li&gt;Spy on inputs/outputs&lt;/li&gt;
&lt;li&gt;Work seamlessly with Angular DI, modules, and modern features like signals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Setting Up Cypress Component Testing&lt;br&gt;
Install Cypress and initialize component testing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install cypress @cypress/angular --save-dev
npx cypress open --component
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Follow the UI wizard to configure your Angular workspace. It will auto-generate a Cypress configuration compatible with Angular.&lt;/p&gt;
&lt;h4 id=&quot;-example-component-with-signals-amp-outputs&quot;&gt;️ Example Component with Signals &amp;amp; Outputs&lt;/h4&gt;
&lt;p&gt;Let's test a simple &lt;code&gt;CounterComponent&lt;/code&gt; that demonstrates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Input binding&lt;/li&gt;
&lt;li&gt;Output emission&lt;/li&gt;
&lt;li&gt;Signals and computed values&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// counter.component.ts
import { Component, Input, Output, EventEmitter, signal, computed } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;{{ title }}&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;Count: {{ count() }}&amp;lt;/p&amp;gt;
      &amp;lt;button (click)=&quot;increment()&quot;&amp;gt;Increment&amp;lt;/button&amp;gt;
      &amp;lt;button (click)=&quot;reset()&quot;&amp;gt;Reset&amp;lt;/button&amp;gt;
      &amp;lt;p&amp;gt;Double: {{ doubleCount() }}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  `
})
export class CounterComponent {
  @Input() title = 'Default Counter';
  @Output() onReset = new EventEmitter&amp;lt;void&amp;gt;();

  private _count = signal(0);
  count = this._count.asReadonly();
  doubleCount = computed(() =&amp;gt; this._count() * 2);

  increment() {
    this._count.set(this._count() + 1);
  }

  reset() {
    this._count.set(0);
    this.onReset.emit();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;basic-cypress-tests&quot;&gt;Basic Cypress Tests&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;✅ Rendering with Default and Custom Inputs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// counter.component.cy.ts
import { mount } from 'cypress/angular';
import { CounterComponent } from './counter.component';

describe('CounterComponent', () =&amp;gt; {
  it('renders with default title', () =&amp;gt; {
    mount(CounterComponent);
    cy.contains('Default Counter');
    cy.contains('Count: 0');
  });

  it('accepts custom title', () =&amp;gt; {
    mount(CounterComponent, {
      componentProperties: { title: 'Custom Counter' }
    });
    cy.contains('Custom Counter');
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;-testing-signals-and-computed-values&quot;&gt;⚖️ Testing Signals and Computed Values&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;it('increments count and updates double', () =&amp;gt; {
  mount(CounterComponent);
  cy.get('button').contains('Increment').click().click();
  cy.contains('Count: 2');
  cy.contains('Double: 4');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;spying-on-output-events&quot;&gt;Spying on Output Events&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;it('emits reset event', () =&amp;gt; {
  const resetSpy = cy.spy().as('resetSpy');

  mount(CounterComponent, {
    componentProperties: {
      onReset: { emit: resetSpy } as any
    }
  });

  cy.get('button').contains('Reset').click();
  cy.get('@resetSpy').should('have.been.calledOnce');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;testing-with-observables&quot;&gt;Testing with Observables&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// message.component.ts
@Component({
  selector: 'app-message',
  template: `&amp;lt;p *ngIf=&quot;message&quot;&amp;gt;{{ message }}&amp;lt;/p&amp;gt;`
})
export class MessageComponent {
  private _message = signal('');
  message = this._message.asReadonly();

  @Input()
  set messageInput$(value: Observable&amp;lt;string&amp;gt;) {
    value.subscribe(msg =&amp;gt; this._message.set(msg));
  }
}
it('renders observable message', () =&amp;gt; {
  const message$ = of('Hello from Observable!');
  mount(MessageComponent, {
    componentProperties: { messageInput$: message$ }
  });
  cy.contains('Hello from Observable!');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;advanced-mocking-techniques&quot;&gt;Advanced Mocking Techniques&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;⚙️ Injecting Angular Services&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class MockLoggerService {
  log = cy.stub().as('logStub');
}

mount(MyComponent, {
  providers: [
    { provide: LoggerService, useClass: MockLoggerService }
  ]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;mocking-http-calls-with-httpclienttestingmodule&quot;&gt;Mocking HTTP Calls with HttpClientTestingModule&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

beforeEach(() =&amp;gt; {
  cy.intercept('GET', '/api/data', { fixture: 'data.json' });
});

mount(MyHttpComponent, {
  imports: [HttpClientTestingModule]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;stubbing-child-components&quot;&gt;Stubbing Child Components&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;@Component({
  selector: 'app-child',
  template: '' // stubbed template
})
class StubChildComponent {}

mount(ParentComponent, {
  declarations: [StubChildComponent]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Cypress Component Testing is a game-changer for Angular developers. By combining the real browser testing experience with Angular’s new reactivity features like signals and computed, we can create robust, testable, and modern UIs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mount Angular components with Cypress easily&lt;/li&gt;
&lt;li&gt;Test signals, computed, observables&lt;/li&gt;
&lt;li&gt;Use spies and stubs for robust unit isolation&lt;/li&gt;
&lt;li&gt;Mock services and HTTP with Angular-friendly tooling&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13405/a-complete-guide-to-angular-component-testing-with-cypress</guid>
<pubDate>Tue, 24 Mar 2026 01:37:36 +0000</pubDate>
</item>
</channel>
</rss>