Why do I get "TypeError: cannot convert symbol value to string" when I try to create a clone of a Vuex store in a Jest unit test?
P粉604848588
2023-08-26 16:06:50
<p>I have a working Vue 2.6 / Vuex 3.6 / TypeScript application. I want to add some unit tests before doing some complex refactoring. Once I had Jest and Vue Test Utils installed and configured, I tried following the instructions provided in the official Vue Test Utils guide. </p>
<p>Adapt the instructions to my specific project, like this: </p>
<pre class="brush:js;toolbar:false;">import { createLocalVue } from '@vue/test-utils'
import Vuex from 'vue'
import store from 'store'
import { cloneDeep } from 'lodash'
test("SET_CURRENT_VTK_INDEX_SLICES should update the VTK index slices", () => {
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store(cloneDeep(storeConfig))
expect(store.state.iIndexSlice).toBe(0)
store.commit('SET_CURRENT_VTK_INDEX_SLICES', { indexAxis: 'i', value: 1 })
})
</pre>
<p>But when I execute <code>npm run test:unit</code> I get the following error: </p>
<blockquote>
<p>"TypeError: cannot convert symbol value to string"</p>
</blockquote>
<p>I don't think there are any symbols in the store, but use a recursive function to check the store and all its children. (I stole this code from somewhere I don't remember): </p>
<pre class="brush:js;toolbar:false;">function findSymbolInStore(store) {
for (const key in store) {
console.log(key);
if (store.hasOwnProperty(key)) {
const value = store[key];
if (typeof value === 'object') {
if (value instanceof Symbol) {
console.log(`Symbol found: ${key}`);
} else {
findSymbolInStore(value);
}
}
}
}
}
findSymbolInStore(store.state);
</pre>
<p>No symbols found in the store.</p>
<p>I hit a few more dead ends and tried stringifying the store to see where the symbols were: </p>
<pre class="brush:js;toolbar:false;">try {
const thisStore = JSON.stringify(store);
} catch (err) {
console.error('Error converting object to string;', err);
}
</pre>
<p>But this throws the error: </p>
<blockquote>
<p>Type error: converting loop structure to JSON</p>
</blockquote>
<p>Then try stringifying with <code>flatted</code>: </p>
<pre class="brush:js;toolbar:false;">import flatted from 'flatted';
const stringifyStore = flatted.stringify(store);
const parsedStore = flatted.parse(stringifyStore);
</pre>
<p>This seemed to get me a step further and now I'm getting the error: </p>
<blockquote>
<p>TypeError: Cannot read property of undefined (read 'iIndexSlice')</p>
</blockquote>
<p>This is strange because I can see that <code>iIndexStore</code> has a default value of 0 in the store. Thankfully, at this point Amit Patel got me on the right track by pointing out that not only <code>iIndexSlice</code> was undefined, but the entire <code>store.state</code> was also undefined. </p>
<p>I stumbled upon a [Vuex GitHub issue][4] with a similar error to the one I encountered: </p>
<blockquote>
<p>[vuex] getters should be functions, but 'getters.currentView' is {}</p>
</blockquote>
<p>In the question referenced above, the author recommends not exporting the store, but only the store's configuration. I realized that the app's store was exporting an actual store instance. The Vuex storage definition looks like this: </p>
<pre class="brush:js;toolbar:false;">const store = new Vuex.Store({
state: {
iIndexSlice: 0,
// ...
},
getters: {
currentView(state) {
// Function code ...
}
mutations: {
// code
},
actions: {
// code
}
});
export default store;
</pre>
<p>But what now? </p>
<p>HT: To Mujeeb, who helped me with some symbolic debugging. </p>
<p> NOTE: I could have skipped the dead ends etc, but I thought others might have the same difficulty and it might be easier to google the answer if some bugs etc were mentioned. </p>
(Welcome to another episode of "Dave spent way too much time fixing this...it's very trivial, but hopefully saves another person who will make the same mistake":
I refactored the Vuex store as follows:
Then I just need to make a small adjustment to the Jest test:
Now the test runs without problems.