"[vuex] поле состояния foo было переопределено модулем с тем же именем в foobar" с помощью вспомогательной функции deepmerge в jest - PullRequest
5 голосов
/ 07 мая 2020

Я использую вспомогательную функцию для создания хранилища внутри моих шуток. Вспомогательная функция использует deepmerge для слияния базовой конфигурации c с настроенной конфигурацией. Это приводит к появлению нескольких предупреждений консоли

[vuex] state field "cart" was overridden by a module with the same name at "cart"
[vuex] state field "customer" was overridden by a module with the same name at "customer"
[vuex] state field "checkout" was overridden by a module with the same name at "checkout"

store. js (уменьшено до минимума для целей презентации)

import cart from './modules/cart'
import checkout from './modules/checkout'
import customer from './modules/customer'

Vue.use(Vuex)

export const config = {
    modules: {
        cart,
        customer,
        checkout,
    },
}

export default new Vuex.Store(config)

test-utils. js

import merge from 'deepmerge'
import { config as storeConfig } from './vuex/store'

// merge basic config with custom config
export const createStore = config => {
    const combinedConfig = (config)
        ? merge(storeConfig, config)
        : storeConfig
    return new Vuex.Store(combinedConfig)
}

с использованием вспомогательной функции внутри

somejest.test. js

import { createStore } from 'test-utils'

const wrapper = mount(ShippingComponent, {
    store: createStore({
        modules: {
            checkout: {
                state: {
                    availableShippingMethods: {
                        flatrate: {
                            carrier_title: 'Flat Rate',
                        },
                    },
                },
            },
        },
    }),
    localVue,
})

Как устранить предупреждение консоли?

Ответы [ 3 ]

2 голосов
/ 15 мая 2020

Ну, я считаю, что нет необходимости использовать deepmerge в test-utils.ts. Лучше использовать сам Vuex для обработки слияния модуля вместо слияния его с другими методами.

необходимо передать требуемый модуль.


import { createStore, createLocalVue } from 'test-utils';
import Vuex from 'vuex';

const localVue = createLocalVue()

localVue.use(Vuex);

// mock the store in beforeEach

describe('MyComponent.vue', () => {
  let actions
  let state
  let store

  beforeEach(() => {
    state = {
      availableShippingMethods: {
        flatrate: {
          carrier_title: 'Flat Rate',
        },
      },
    }

    actions = {
      moduleActionClick: jest.fn()
    }

    store = new Vuex.Store({
      modules: {
        checkout: {
          state,
          actions,
          getters: myModule.getters // you can get your getters from store. No need to mock those 
        }
      }
    })
  })
});

свисток, В тестовых случаях:

const wrapper = shallowMount(MyComponent, { store, localVue })

Надеюсь, это поможет!

2 голосов
/ 17 мая 2020

Я считаю, что в данном случае предупреждение вводит в заблуждение. Это технически верно, но бесполезно.

Следующий код выдаст такое же предупреждение. Он не использует deepmerge, vue-test-utils или jest, но я считаю, что причина root такая же, как и в исходном вопросе:

const config = {
  state: {},

  modules: {
    customer: {}
  }
}

const store1 = new Vuex.Store(config)
const store2 = new Vuex.Store(config)
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@3.4.0/dist/vuex.js"></script>

В этом примере есть две ключевые части, которые необходимы для запуска предупреждения:

  1. Несколько хранилищ.
  2. A root state объект в конфигурации.

Код в вопросе определенно имеет несколько хранилищ. Один создается в конце store.js, а другой создается createStore.

В вопросе не отображается объект root state, но он упоминает, что код был уменьшено. Я предполагаю, что в полном коде есть этот объект.

Так почему это вызывает это предупреждение?

Модуль state хранится в объекте root state. Несмотря на то, что модуль в моем примере явно не имеет state, он все еще существует. Этот state будет сохранен в state.customer. Поэтому, когда создается первое хранилище, оно добавляет свойство customer к этому root state объекту.

Пока нет проблем.

Однако, когда создается второе хранилище он использует тот же объект root state. Копирование или объединение конфигурации на этом этапе не поможет, потому что скопированный state также будет иметь свойство customer. Второй магазин также пытается добавить customer к root state. Однако он обнаруживает, что свойство уже существует, путается и регистрирует предупреждение.

В официальной документации есть некоторые сведения об этом:

https://vuex.vuejs.org/guide/modules.html#module -reuse

Самый простой способ исправить это - использовать вместо этого функцию для root state:

state: () => ({ /* all the state you currently have */ }),

Каждый магазин будет вызывать эту функцию и получать свою собственную копию штат. Это то же самое, что использовать функцию data для компонента.

Если вам на самом деле не нужно root state, вы также можете исправить это, просто удалив его полностью. Если state не указано, Vuex будет каждый раз создавать новый объект root state.

2 голосов
/ 11 мая 2020

Регистрируется, когда имя свойства в состоянии конфликтует с именем модуля, например:

new Vuex.Store({
  state: {
    foo: 'bar'
  },
  modules: {
    foo: {}
  }
})

, поэтому возникает предупреждение.


new Vuex.Store(({
  state: {
    cart: '',
    customer: '',
    checkout: ''
  },
  modules: {
    cart: {},
    customer: {},
    checkout: {},
  }
}))


скорее всего, здесь

export const createStore = config => {
    const combinedConfig = (config)
        ? merge(storeConfig, config)
        : storeConfig
    return new Vuex.Store(combinedConfig)
}

из исходного кода vuex, это помогает указать, где возникают эти ошибки для ведения журнала.

Если вы запускаете приложение в производственной среде, вы знаете, что это предупреждение не будет появляться ... или вы потенциально можете перехватить предупреждение и немедленно вернуться;

исходный код vuex

const parentState = getNestedState(rootState, path.slice(0, -1))
const moduleName = path[path.length - 1]
store._withCommit(() => {
  if (__DEV__) {
    if (moduleName in parentState) {
      console.warn(
        `[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"`
      )
    }
  }
  Vue.set(parentState, moduleName, module.state)
})

тесты vuex

jest.spyOn(console, 'warn').mockImplementation()
const store = new Vuex.Store({
  modules: {
    foo: {
      state () {
        return { value: 1 }
      },
      modules: {
        value: {
          state: () => 2
        }
      }
    }
  }
})
expect(store.state.foo.value).toBe(2)
expect(console.warn).toHaveBeenCalledWith(
  `[vuex] state field "value" was overridden by a module with the same name at "foo.value"`
)
...