1

I am trying to prove that the price is being set on the component.

I have the following HTML:

<template>
    <h1>Current price of a bitcoin in Euro</h1>
    <lightning-formatted-number currency-code="EUR"
                                format-style="currency"
                                value={euroPrice}
    ></lightning-formatted-number>
</template>

And the following JavaScript:

import {LightningElement, api, track} from 'lwc';

const bitcoinPriceProvider = 'https://api.coinbase.com/v2/prices/spot?currency=EUR';
export default class BitcoinEuroPrice extends LightningElement {
    @api
    refreshRateInSeconds;

    @track
    euroPrice;

    connectedCallback() {
        this.fetchPrice();
        setInterval(this.fetchPrice, this.refreshRateInSeconds * 1000);
    }

    fetchPrice() {
        fetch(bitcoinPriceProvider)
            .then(response => response.json())
            .then(json => {
                this.euroPrice = json.data.amount;
                console.log('######## this.euroPrice: ', this.euroPrice);
            });
    }
}

This is my test:

import {createElement} from 'lwc';
import BitcoinEuroPrice from 'c/bitcoinEuroPrice';

describe('c-bitcoinEuroPrice', () => {
    afterEach(() => {
        while (document.body.firstChild) {
            document.body.removeChild(document.body.firstChild);
        }
    });

    it('fetches price', () => {
        // Arrange
        const testAmount = '8448.947391885';
        const mockApiResponse = {
            'data': {
                'base': 'BTC',
                'currency': 'EUR',
                'amount': testAmount
            }
        };
        fetch = global.fetch = mockFetch(mockApiResponse);

        // Act
        const priceUnderTest = createElement('c-bitcoinEuroPrice', {
            is: BitcoinEuroPrice
        });
        document.body.appendChild(priceUnderTest);

        // Assert
        expect(global.fetch).toHaveBeenCalledTimes(1);
        expect(global.fetch).toHaveBeenCalledWith('https://api.coinbase.com/v2/prices/spot?currency=EUR');

        const displayPrice = priceUnderTest.shadowRoot.querySelector('lightning-formatted-number');
        console.log('##### priceUnderTest', priceUnderTest);
        console.log('##### displayPrice', displayPrice);
        expect(displayPrice.value).toEqual(testAmount);
    });

    function mockFetch(mockApiResponse) {
        return jest
            .fn()
            .mockImplementationOnce(() =>
                Promise.resolve({
                    ok: true,
                    json: () => Promise.resolve(mockApiResponse),
                    jsonResponse: mockApiResponse
                })
            );
    }
});

This fails with:

expect(received).toEqual(expected) // deep equality

Expected: "8448.947391885"
Received: undefined

  34 |         console.log('##### priceUnderTest', priceUnderTest);
  35 |         console.log('##### displayPrice', displayPrice);
> 36 |         expect(displayPrice.value).toEqual(testAmount);
     |         ^
  37 |     });
  38 |

but further down the log I see:

console.log force-app/main/default/lwc/bitcoinEuroPrice/bitcoinEuroPrice.js:21 ######## this.euroPrice: 8448.947391885

My hypothesis is that the test is not waiting for the asynchronous chain to complete before checking the value.

How can I make it wait? Or is there some other way I should check the value?

4

Figured out a way to flush the promises by applying answer from https://stackoverflow.com/questions/44741102/how-to-make-jest-wait-for-all-asynchronous-code-to-finish-execution-before-expec

essentially just needed to:

  1. Add this function/constant:
const flushPromises = () => new Promise(setImmediate);
  1. Make the test async:
it('fetches price', async () => {
  1. Wait for the flush:
        document.body.appendChild(priceUnderTest);
        await flushPromises();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.