Jest testing: custom currency/decimal formatters showed wrong delimiters - reactjs

I tried to switch to Jest-testing inside of our React application.
Lots of mocha and enzyme tests are working with small fixes.
With tests for a currency formatting component I get the wrong culture format inside the tests. I expect the result to be in format:
1.234.567,89 €
but I receive:
1,234,567.89 €
In the application I get all values formatted nicely in German formats as expected.
BTW:
Inside of a helper method we use following code for internal formatting
value.toLocaleString(['de-DE'], {
style: 'decimal',
useGrouping: true,
minimumFractionDigits: 2,
maximumFractionDigits: 2
})

I've got it...
Because Jest is using Node for testing and Node doesn't support other locales than 'en', I need to add Intl/IntlPolyfill inside a Jest setup file.
const areIntlLocalesSupported = require('intl-locales-supported');
const localesMyAppSupports = [
'de'
];
if (global.Intl) {
// Determine if the built-in `Intl` has the locale data we need.
if (!areIntlLocalesSupported(localesMyAppSupports)) {
// `Intl` exists, but it doesn't have the data we need, so load the
// polyfill and patch the constructors we need with the polyfill's.
const IntlPolyfill = require('intl');
Intl.NumberFormat = IntlPolyfill.NumberFormat;
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
Number.prototype.toLocaleString = IntlPolyfill.__localeSensitiveProtos.Number.toLocaleString;
Date.prototype.toLocaleString = IntlPolyfill.__localeSensitiveProtos.Date.toLocaleString;
}
} else {
// No `Intl`, so use and load the polyfill.
global.Intl = require('intl');
}
I don't know the reason, but I need to explicitly overwrite Number.prototype.toLocaleString and Date.prototype.toLocaleString.

Related

VSCode incorrectly inserting semi-colons in React Typescript project when formatting on save with Prettier

I am working with React and Typescript in VSCode, using Prettier as the default formatter. Inside my ~/.vscode/settings.json, I have it set to format the document on save:
{
"typescript.tsdk": "node_modules\\typescript\\lib",
"cmake.configureOnOpen": false,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "modifications",
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true,
"source.sortMembers": true
}
}
This worked for a long time without issue, however for some reason, maybe a bug, lately I have been experiencing the insertion of semi-colons in nonsensical locations, for instance following a callback block passed into the argument of UseCallback. Curiously, on the first save it will just move the dependency array to the next line, but on subsequent saves it adds the semicolon:
Initial format
const myCallback = useCallback(() => {
return myDependency1 + myDependency2 + myDependency3 + myDependency4 > 0;
},[myDependency1, myDependency2, myDependency3, myDependency4])
Following one save
const myCallback = useCallback(() => {
return myDependency1 + myDependency2 + myDependency3 + myDependency4 > 0;
},
[myDependency1, myDependency2, myDependency3, myDependency4])
Following second save
const myCallback = useCallback(() => {
return myDependency1 + myDependency2 + myDependency3 + myDependency4 > 0;
};,
[myDependency1, myDependency2, myDependency3, myDependency4])
This is breaking the code as it is an illegal character so I am having to set "editor.formatOnSave": false to prevent this happening which is not ideal.
What is strange is that I can Ctrl+Shift+P > Format Document or Format Document with... then selecting Prettier - and the file is fixed without adding the problematic semicolons.
I have also tried using // prettier-ignore and //eslint-disable-next-line but this is not changing the behaviour.
Perhaps that this is a bug pushed to the Prettier extension, VSCode, or another extension or library (ESLint perhaps?) - though I can't find the issue listed on any of these project on GitHub. Therefore my real question is what can I do to figure out what is causing this so I can report it to the correct project or perhaps just fix whatever misconfiguration I have made?

How do I make a query to get multiple content type in spfx? #pnp

I am making a project with React and Typescript (SPFX) and I have created a webpart with about 4 components and each component has a different Content type id. At the moment, I need to make a query search every time I want to get the CT information in each component, like this:
const searchNews = async () => {
const searchQuery: ISearchQuery = {
Querytext: [
'ContentTypeId:0x010100C568DBD9B2FDCC96666E9F2007948130EC3DB054237AF39005CF914A33608B74B8D05F01*',
'ANFHighlightOWSBOOL=1'
].join(' '),
RowLimit: 10,
SelectProperties: [
'Title',
'Path',
'ANFHighlightOWSBOOL',
'ANFImageOWSIMGE',
'AuthorOWSUSER',
'CreatedOWSDate'
]
};
They have mostly all the same SelectProperties, with specific differences.
I saw we can do a query in the webpart property pane to have a CT dynamic return so we can access it in the component. I also saw this tutorial: https://learn.microsoft.com/en-us/sharepoint/dev/spfx/dynamic-data But I am not quite sure how to make it and if there is a way to do it without de dynamic import.
How can I do a query in the property pane and make it usable in all my possible components?

StencilJS unit testing keyboard event?

I want to write unit tests for my custom web-components in stencilJs but have no idea how to do it the right way. Here's what I did so far!
.tsx
...
valueFormat(event: Event): void {
const val = (event.target as HTMLInputElement).value;
const format = Number.parseInt(val, 10);
const newVal = format.toLocaleString(undefined, {
minimumFractionDigits: 2,
});
this.value = newVal;
}
.spec.tsx
it('should format value', async () => {
const comp = new MyComponent();
const spy = jest.spyOn(comp, 'valueFormat');
comp.myInputEvent.emit();
expect(spy).toHaveBeenCalled();
});
I want to test the case, when I type a number in the input field that it format it. So my valueFormat() method, I spying on should be called when a Keyboard event is firing. I hope you can help me out!
If you want to test it with Event in mind, I would strongly recommend you to use newSpecPage(https://stenciljs.com/docs/unit-testing) - as this will allow you to construct your component DOM in memory and allow you to test its logic (so you can easily trigger event like click, keyboard or trigger input value change which I assume where your valueFormat() method get called/binded?)
Another approach is to move formatting logic to separate function which takes just input value as an argument like:
formatInputValue(value: string) {
const format = Number.parseInt(value, 10);
const newVal = format.toLocaleString(undefined, {
minimumFractionDigits: 2,
});
return newVal;
}
then you could easily unit test this method by simply constructing component and then calling the method with whatever the value you want to test with (this is useful if you want to test edge cases like null, empty value, non numeric value etc.)
Personally I wouldn't bother creating function as conversion logic seem to be simple - also one advantage of doing testing via DOM (using newSpecPage()) is that if you ever want to change your formatting logic, amount of test code you need to update could be quite small, meaning your test code is bit more maintainable (again just my personal opinion, it's all depends on how complex the formatting logic or the expected input be)

Using String objects in react-native

I am working on moving all my core business logic to a model layer, which would be used across all my projects.
My project set mainly comprises of a web client-facing application built on Reactjs, few internal tools also built on Reactjs, and a mobile application built on react-native.
In my model layer, I have created custom data types to handle null/empty scenarios from backend and also to add custom format functions.
Following is the code for a string model which I have built.
/**
Author - Harkirat Saluja
Git - https://bitbucket.org/salujaharkirat/
**/
"use strict";
class CustomString {
static init (value = "") {
if (value === null) {
value = "";
}
const s = new String(value);
s.__proto__.upperCaseFormat = function () {
return this.toUpperCase();
};
return s;
}
}
export default WealthyString;
The way I invoke this is as follows:-
const firstName = WealthyString.init(firstName);
const lastName = WealthyString.init(lastName);
Now, if we see this returns a string object.
In my web project, I use this as follows in the react component, and it works nice and fine.
<span>{firstName}{" "} {lastName}</span>
But, in my react-native project, if I use it in the same way, it throws this error. Also, this error only comes when remote debugging if off and not when I am connected to chrome debugger.
<Text>{firstName}{" "} {lastName}</Text>
So, in order to resolve this for now, where strings are appended as the way shown above I have used toString(). But I was wondering is there something wrong the library or am I missing something?
Update
So looks like String objects are not working with Text in react-native at all. So to fix this I do the following:-
const SecondaryText = ({style, children}) => {
const styleCopy = addLineHeightToStyle(style, 14);
let dupChildren = children;
if (dupChildren instanceof String) {
dupChildren = dupChildren.toString();
}
return (
<ReactNative.Text
allowFontScaling={false}
style={[styles.secondaryText, styleCopy]}
>
{dupChildren}
</ReactNative.Text>
);
};
Built a wrapper over Text which react-native provides and convert the object to a string inside this.
Concatenate string using template literals in case of string combination.
Consider use template literals for complicated string. Eg:
<Text>{`${firstname} ${lastname}`}</Text>
Do you want to change this as follows?
<Text>{firstName +" "+lastName}</Text>
There are multiple ways you can do this. Write a function and return the concatenated string.
const test = (firstName ,lastName) => {
return firstName+lastName
}
If you have a class, you can do like this inside your render function.
<Text>{this.test()}</Text>

E2E test using Entities

I'm trying to optimize my E2E tests to incorporate the usage of entities.
Our tests are basically filling data into a form on a webpage. Our tests are using the PageObject method where our PageObject stores our elements in variables and we also have variables containing the interactions with the elements stored in the PO file.
Our spec file is what calls the PO file and inputs the data into each element similar to(this is just examples of what we are doing):
PO File:
this.firstNameField = by.model('firstName');
this.lastNameField = by.model('lastName');
this.setFirstNameField = function(firstname) {
element(this.firstNameField).sendKeys(firstname);
};
this.setLastNameField = function(lastname) {
element(this.lastNameField).sendKeys(lastname);
};
Spec file:
pageObject.setFirstNameField('TestName');
pageObject.setLastNameField('TestLastName');
In our spec file, we have roughly 100 lines of this code which is not very effecient from what I can tell. I want to remove this style and use Entity's instead, however I'm not sure exactly how i would go about this, hence why I'm coming here.
A friend of mine gave me a hint of how i'd go about this and here is what he has provided me:
spec file:
var nameEntity = {
firstName: 'TestName',
lastName: 'TestLastName'
};
pageObject.PopulateUIWithNameEntity(nameEntity);
Now i know i can switch the nameEntity to be stored in the pageObejct file, however i'm not exactly sure how the PopulateUIWIthNameEntity should be created.
I've tried the following but I can't seem to get it to input the values from the nameEntity into the element itself.
pageObject File:
this.PopulateUIWithNameEntity = function(nameEntity) {
element(this.setFirstNameField).sendKeys(nameEntity);
};
You were close... just needed a little refactor.
Adding your test data to an object (hash) is definitely a good idea. Then you just need to extract the elements from it in your method. You also already have individual methods for each individual action... so you just needed to use them.
spec...
var nameEntity = {
firstName: 'TestName',
lastName: 'TestLastName'
};
pageObject.populateUIWithNameEntity(nameEntity);
page object...
this.populateUIWithNameEntity = function(nameEntity) {
this.setFirstNameField(nameEntity.firstName);
this.setLastNameField(nameEntity.lastName);
};

Resources