stencil-store
stencil-store copied to clipboard
bug: Type error when running tests for component with onChange listener
Prerequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already report this problem, without success.
Stencil Store Version
2.0.0
Stencil Version
2.13.0
Current Behavior
When a component has an onChange listener which has a function that manipulates a https://github.com/State property:
import { onChange } from '../a-store';
export class AppProfile {
@State() something = 0;
componentWillLoad() {
onChange('clicks', (value) => {
this.something++;
});
}
// ...
}
when I try to unit test the component I get a type error like:
● app-profile › clicks the button again
TypeError: Cannot read properties of undefined (reading '$instanceValues$')
12 | componentWillLoad() {
13 | onChange('clicks', (value) => {
> 14 | this.something++;
| ^
15 | });
16 | }
17 |
at getValue (node_modules/@stencil/core/internal/testing/index.js:538:282)
at AppProfile.get [as something] (node_modules/@stencil/core/internal/testing/index.js:565:13)
at src/components/app-profile/app-profile.tsx:14:7
at node_modules/@stencil/store/dist/index.js:144:43
at node_modules/@stencil/store/dist/index.js:88:40
at Array.forEach (<anonymous>)
at reset (node_modules/@stencil/store/dist/index.js:88:24)
at Object.dispose (node_modules/@stencil/store/dist/index.js:94:9)
at Object.<anonymous> (src/components/app-profile/app-profile.spec.ts:7:5)
The error only occurs if I'm referencing a @State property, if I reference a component method that just logs something, for example, there is no error.
However, this error doesn't happen with the first test in the suite, only subsequent tests. I'm calling store.dispose() before each test.
Expected Behavior
Tests should run without throwing an error and failing.
Steps to Reproduce
Download repo, run npm install
then npm run test
OR
-
Create a component which registers an
onChange
listener that references a@State
variable -
Write a unit test suite for the component with at least 2 tests
-
Run the unit tests
Code Reproduction URL
https://github.com/samshareski/store-test-bug
Additional Information
No response
Hello @samshareski! Thanks for filing this issue and for providing a helpful reproduction. I can confirm that the bug you described is happening, and after a bit of investigation I'm not sure what the source of the problem is but I believe there may be a bug in stencil-store's logic w/ the onChange
handler, with variable scope and this
binding, or something along those lines.
I'm going to label this for further investigation and ingestion into our backlog.
Thanks again for reporting!
@samshareski are you using store.dispose()
between tests?
@samshareski are you using
store.dispose()
between tests?
yes
Do you have a repo with a reproduction of this issue I can take a look into?
Do you have a repo with a reproduction of this issue I can take a look into?
it's linked in the first comment
the failing tests are in this spec https://github.com/samshareski/store-test-bug/blob/master/src/components/app-profile/app-profile.spec.ts
I see what's going on. Handlers are never disposed, you need to unregister them in your component. onChange
returns a function that when called will unregister everything.
@Serabe https://github.com/samshareski/store-test-bug/commit/24be6fef71b777f6e3f1b3dfca276b46b2832368 is this how that would be set up?
this version still has the test failures occurring
Yes. I'll need to investigate then.
@Serabe I believe this is a bug in stencil itself, so I believe this issue can be closed and cross referenced in stencil:
https://github.com/ionic-team/stencil/issues/4053
As a workaround, in your spec tests, you can manually call disconnectedCallback
:
page.rootInstance.disconnectedCallback();
Hey @ajgagnon, I tried calling page.rootInstance.disconnectedCallback();
in my jest test like this:
afterEach(() => {
page.rootInstance.disconnectedCallback();
});
unfortunatly I get an TypeError: page.rootInstance.disconnectedCallback is not a function
after each run. Do you maybe have a working example?
@christophsaile This is probably because you do not have a disconnectedCallback in your component. You need to add this method to your component:
private removeListener: any;
componentWillLoad() {
this.removeListener = onChange('clicks', (value) => {
this.something++;
});
}
disconnectedCallback() {
this.removeListener();
}