Skip to content

Instantly share code, notes, and snippets.

@florestankorp
Last active January 29, 2025 15:46
Show Gist options
  • Save florestankorp/e7539ddc953c02a3e8d20f5b1336a9a7 to your computer and use it in GitHub Desktop.
Save florestankorp/e7539ddc953c02a3e8d20f5b1336a9a7 to your computer and use it in GitHub Desktop.
Minimal example of effect
/* eslint-disable max-classes-per-file */
/* eslint-disable @angular-eslint/component-selector */
import {
ChangeDetectionStrategy,
Component,
effect,
inject,
Injectable,
OnInit,
signal,
WritableSignal,
} from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class ServiceOne {
public signalOne$ = signal(1);
}
@Injectable({
providedIn: 'root',
})
export class ServiceTwo {
public signalTwo$ = signal(2);
private readonly serviceOne = inject(ServiceOne);
public updateSignalTwo(): void {
this.signalTwo$.update((value) => {
return value + this.serviceOne.signalOne$();
});
}
}
@Component({
selector: 'my-component',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '',
standalone: true,
})
export class MyComponent implements OnInit {
public signalTwo$!: WritableSignal<number>;
private readonly serviceTwo = inject(ServiceTwo);
public constructor() {
effect(() => {
// / I want to spy on `updateSignalOne` and make sure it gets called when I update someSignalTwo$, which depends on someSignalOne$, but doesn't come from a service that is being injected into this component!
this.serviceTwo.updateSignalTwo();
});
}
public ngOnInit(): void {
this.signalTwo$ = this.serviceTwo.signalTwo$;
}
}
@florestankorp
Copy link
Author

The test I want to write:

my-component.spec.ts

it('should update signalTwo when effect runs', () => {
  mockSignalOne$.update(() => 2);
  expect(updateSignalTwoSpy).toHaveBeenCalledTimes(2);
});

@florestankorp
Copy link
Author

florestankorp commented Jan 29, 2025

Working test using ng-mocks

describe('MyComponent', () => {
  const mockSignalOne$ = signal(1);
  const mockSignalTwo$ = signal(2);

  const updateSignalTwoSpy = jest.fn().mockImplementation(() => {
    mockSignalTwo$.update((value) => {
      return value + mockSignalOne$();
    });
  });

  beforeEach(async () => {
    return MockBuilder(MyComponent).mock(ServiceTwo, {
      updateSignalTwo: updateSignalTwoSpy,
      signalTwo$: mockSignalTwo$,
    });
  });

  it('should update signalTwo when effect runs', () => {
    const fixture = MockRender(MyComponent);

    mockSignalOne$.update(() => 2);
    fixture.detectChanges();

    expect(updateSignalTwoSpy).toHaveBeenCalledTimes(2);
  });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment