Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(signals): signals testing package with provideMockSignalStore #4252

Closed

Conversation

gergelyszerovay
Copy link

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

There is no auto-mock functionality for easily mock NgRx's SignalStores and ComponentStores. This PR contains the provideMockSignalStore function that provides a mock version of a SignalStore:

  • Signals are replaced by WritableSignals
  • RxMethods are replaced by FakeRxMethods
  • Functions are replaced by Sinon fakes

We can use the mocked SignalStores in unit tests, Storybook stories and Storybook Play tests.

FakeRxMethods are generated by the newMockRxMethod() function. A FakeRxMethod is a function, that accepts a static value, signal, or an observable as an input argument. It has a FAKE_RX_METHOD property, contains a Sinon fake. This Sinon fake stores the call information, when:

  • the FakeRxMethod was called with a static value
  • the FakeRxMethod was called with a signal argument, and the signal's value changes
  • the FakeRxMethod was called with an observable argument, and the observable emits

The only limitation of provideMockSignalStore is that it can't alter the OnInit and OnDestroy hooks. To work around this limitation, I think it's a good practice to do the init/destroy tasks and connect the stores (if there are app / feature / component level stores) from the smart component that consumes the store. Alternatively, I can modify the signal-store.ts to support the mocking of the OnInit and OnDestroy hooks.

I covered the feature with unit tests, and here are some additional examples where I use provideMockSignalStore on real components:

I'll soon publish an article that explains how these examples work.

I'll create a separate PR for the provideMockComponentStore function, its source is available here, it works but needs some polishing. It uses the same FakeRxMethod as this PR for replacing the updates and effects of the ComponentStore.

Related issue: #2767

I reused some parts (mostly types) of this PR: #3646 "feat(component-store): add a testing library", and I also read the feedback there, for example I use Sinon as @LayZeeDK suggested.

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the current behavior?

What is the new behavior?

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

Copy link

netlify bot commented Feb 19, 2024

Deploy Preview for ngrx-io canceled.

Built without sensitive environment variables

Name Link
🔨 Latest commit ebd2e89
🔍 Latest deploy log https://app.netlify.com/sites/ngrx-io/deploys/65d312d54113c4000826e310

@markostanimirovic
Copy link
Member

Hi @gergelyszerovay,

Thanks for the PR! However, several steps are required before raising a PR. 🙂

Can you please open a feature request and provide the description of the APIs you want to introduce in the @ngrx/signals package?

Read more about submitting a feature request in our contribution guidelines:

  1. Submit a feature request with a detailed explanation and examples of the feature you want to introduce.
  2. The feature will be considered and discussed by the community and team.
  3. If the feature request is approved, it's ready for creating a PR.

@gergelyszerovay
Copy link
Author

Thanks so much for your comment @markostanimirovic, I've seen that @rainerhahnekamp has just created this issue: #4256. Can I use this issue for the feature request as Rainer suggested in his last comment?

I'll reply to Rainer's suggestion on the dependency to sinon.js, and add a detailed description of how my prototype works.

I'm very much looking forward to the feedback of the maintainers and the community, and of course I'd gladly improve any parts of the feature based on this feedback.

And just one more thing: I'm well aware of the fact that it's always a hard decision what to include in a software, so if you decide to decline my feature request, I'm going to release it separately.

@markostanimirovic
Copy link
Member

Sure, let's use the opened feature request to discuss the potential testing plugin.

I'm going to close this PR for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants