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>
I have 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;
});
}
}
And I have the following metadata:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<description>Bitcoin Euro Price</description>
<isExposed>true</isExposed>
<masterLabel>Bitcoin Euro Price</masterLabel>
<targets>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
<targetConfigs>
<targetConfig targets="lightningCommunity__Default">
<property name="refreshRateInSeconds" type="Integer" default="10"/>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
I am currently trying to figure out how to enhance my test to confirm setInterval(this.fetchPrice, this.refreshRateInSeconds * 1000);
is executing as expected.
In the metadata, I have given refreshRateInSeconds
a default of 10
.
My test currently looks like this:
import {createElement} from 'lwc';
import BitcoinEuroPrice from 'c/bitcoinEuroPrice';
const priceUnderTest = createElement('c-bitcoinEuroPrice', {
is: BitcoinEuroPrice
});
const testAmount = '8448.947391885';
describe('c-bitcoinEuroPrice', () => {
afterEach(() => {
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
});
it('fetches price and sets the value', async () => {
// Arrange
jest.useFakeTimers();
fetch = global.fetch = mockFetch({
'data': {
'base': 'BTC',
'currency': 'EUR',
'amount': testAmount
}
});
// Act
document.body.appendChild(priceUnderTest);
// Assert
await flushPromises();
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');
expect(displayPrice.value).toEqual(testAmount);
jest.advanceTimersByTime(10000);
expect(global.fetch).toHaveBeenCalledTimes(2);
});
});
function mockFetch(mockApiResponse) {
return jest
.fn()
.mockImplementationOnce(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(mockApiResponse),
jsonResponse: mockApiResponse
})
);
}
function flushPromises() {
return new Promise(setImmediate);
}
The test fails with:
expect(jest.fn()).toHaveBeenCalledTimes(expected) Expected number of calls: 2 Received number of calls: 1 39 | 40 | jest.advanceTimersByTime(10000); > 41 | expect(global.fetch).toHaveBeenCalledTimes(2); | ^ 42 | }); 43 | }); 44 |
I can tell from my log that refreshRateInSeconds
is not catcing the value from the metadata:
console.log force-app/main/default/lwc/bitcoinEuroPrice/bitcoinEuroPrice.js:13 #### this.refreshRateInSeconds:undefined
How can I ensure refreshRateInSeconds
has a value?
If I hardcode a value for refreshRateInSeconds and change mockImplementationOnce
to mockImplementation
, this test should work....