Search code examples
vue.jsjestjsvue-test-utilsshopware6

Shopware 6, jest test with vue-test-utils: unexpected behaivor on render template


This is fragmented/fantasy code to describe only the relevant passages

tests/my-component.spec.js

import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';

import stateMyPluginStore from '../my-component/state';
import stateProductDetail from '...' // the original state from Shopware
...

const product = {
    purchasePrices: [
        {
            net: 15
        }
    ]
};

const productComponent = function(id, purchasePriceNet = 0, purchaseUnitCount = 0, unitId = null) {
    let component = {
        id: 'component_product_ident_' + id,
        name: 'component_name_' + id,
        purchasePrices: [
            {
                net: purchasePriceNet
            }
        ],
        extensions: {
            productPriceConfigurator: {
                purchaseUnitCount: purchaseUnitCount
            }
        }
    }

    if(unitId) {
        component.unitId = unitId
    }

    return component;
}

describe('PriceConfiguratorPurchasePricesView', () => {
    const localVue = createLocalVue();
    localVue.use(Vuex);
    let wrapper = null;

    beforeEach(() => {
        Shopware.State.registerModule('swProductDetail', stateProductDetail)
        Shopware.State.registerModule('MyPluginStore', stateMyPluginStore)
    });

    afterEach(() => {
        Shopware.State.unregisterModule('MyPluginStore')
        Shopware.State.unregisterModule('swProductDetail')

        if(wrapper) {
            wrapper.destroy();
            wrapper = null;
        }
    });

    it('should update list', async () => {
        Shopware.State.commit(
            'swProductDetail/setProduct', {
                purchasePrices: [
                    {
                        net: 10
                    }
                ]
            }
        )
        Shopware.State.commit(
            'MyPluginStore/setProductComponents', [
                productComponent(2, 1.10, 1, 'unitId_2'),
            ]
        )
        wrapper = shallowMount(await Shopware.Component.build('my-plugin'), {
            localVue,
            mocks: {
                ...
            },
            stubs: {
                ...
            },
            provide: {
                validationService: {},
                repositoryFactory: {
                    create: (entity) => ({
                        search: () => {
                            if(entity === 'unit') {
                                const response = {
                                    total: 2
                                };
                                return Promise.resolve(response)
                            }
                        },
                        get: () => {
                            if(entity === 'unit') {
                                const response = {
                                    "translated": {
                                        "shortCode": "kg",
                                        "name": "Kilogramm",
                                        "customFields": {}
                                    }
                                };
                                return Promise.resolve(response)
                            }
                        }
                    })
                }
            },
        });
        await wrapper.setData({}).then(() => {})

        console.log(wrapper.html())
        expect(wrapper.findAll('fieldset').length).toEqual(1);
    });
})

First step in test configuration, default state commits are executed to have some data available. Result:

  • console.log(wrapper.html()) without await wrapper.setData({}).then(() => {})
<div class="sw-container" style="justify-items: stretch; align-items: stretch;" id="purchaseCalculatorTemplate"><br>
  <sw-skeleton-stub></sw-skeleton-stub>
</div>
  • console.log(wrapper.html()) with await wrapper.setData({}).then(() => {})
<div class="sw-container" style="justify-items: stretch; align-items: stretch;" id="purchaseCalculatorTemplate">
      <fieldset class="">
        <div class="sw-container container-input-fields" style="grid-template-columns: 3fr 1fr 3fr 1fr 3fr; justify-items: stretch; align-items: stretch;" data-product="component_product_ident_2">
          <div class="sw-container sw-field sw-block-field sw-contextual-field sw-field--number sw-field--default" style="justify-items: stretch; align-items: stretch;">
            <div class="sw-field sw-block-field sw-contextual-field sw-field--number is--disabled sw-field--default">
              <div class="sw-field__label">
                <!----> <label for="sumProductComponentUnitPurchase_0" class="">
                  ∑ ["terms.purchasePrice.name"] (["terms.net.name"])
                </label>
                <!---->
              </div>
              <div class="sw-block-field__block">
                <!----> <input id="sumProductComponentUnitPurchase_0" name="sumProductComponentUnitPurchase_0" type="text" placeholder="" disabled="disabled" autocomplete="off">
                <div class="sw-field__addition">
                  <!---->
                </div>
              </div>
              <!---->
              <!---->
            </div>
          </div>
        </div>
      </fieldset>
    </div>

Question Why does the wrapper render as expected (with available comit data) only if set await wrapper.setData({}).then(() => {}) and how to fix it?


Solution

  • By awaiting setData you're also awaiting another tick needed to render the content, e.g. when the initial state is showing a loading indicator.

    You can either use the nextTick function to await the upcoming tick, but it may be necessary to await multiple ticks until the desired state is achieved...

    wrapper = shallowMount(await Shopware.Component.build('my-plugin'), {});
    await wrapper.vm.$nextTick();
    console.log(wrapper.html());
    

    ...or you can use the global flushPromises function to await all subsequent promises/ticks.

    wrapper = shallowMount(await Shopware.Component.build('my-plugin'), {});
    await flushPromises();
    console.log(wrapper.html());