Jest, match to regex - javascript

Currently I have this test:
import toHoursMinutes from '../../../app/utils/toHoursMinutes';
describe('app.utils.toHoursMinutes', () => {
it('should remove 3rd group of a time string from date object', async () => {
expect(toHoursMinutes(new Date('2020-07-11T23:59:58.000Z'))).toBe('19:59');
});
});
What toHoursMinutes does is to receive a Date object and transform it like this way:
export default (date) => `${('' + date.getHours()).padStart(2, '0')}:${('' + date.getMinutes()).padStart(2, '0')}`;
My local time offset is -4 so my test pass ok if I compare 23:59 with 19:59, but I want to run the test anywhere, so I prefer to compare the output of toHoursMinutes() with a regex expression like this one, that check the hh:mm format: ^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$
But how can I use a regex to compare instead a explicit string?
I tried this:
const expected = [
expect.stringMatching(/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/)
];
it.only('matches even if received contains additional elements', () => {
expect(['55:56']).toEqual(
expect.arrayContaining(expected)
);
});
But I get a:
Expected: ArrayContaining [StringMatching /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/]
Received: ["55:56"]

There is a toMatch function on expect() that does just that.
expect('12:59').toMatch(/^\d{1,2}:\d{2}$/); // stripped-down regex
https://jestjs.io/docs/expect#tomatchregexp--string
If you want to match a regex inside of other jest functions, you can do so by using expect.stringMatching(/regex/).
expect({
name: 'Peter Parker',
}).toHaveProperty('name', expect.stringMatching(/peter/i))
https://jestjs.io/docs/expect#expectstringmatchingstring--regexp

I was ok except in the dummy data because wasn't for the regex. In case anyone need it, this works:
const expected2 = [
expect.stringMatching(/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/)
];
it('matches even if received contains additional elements', () => {
expect(['12:59']).toEqual(
expect.arrayContaining(expected2)
);
});

In my case, I can check the format of a time in a span using toHaveTextContent().
const span = screen.getByRole("presentation", { name: /time/i });
expect(span).toHaveTextContent(/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/);
Docs for toHaveTextContent(): https://github.com/testing-library/jest-dom#tohavetextcontent

Related

Javascript JSON.stringify method removes trailing zero if object has value as x.0 ( like 6.0 ) [duplicate]

I am working on a project where I require to format incoming numbers in the following way:
###.###
However I noticed some results I didn't expect.
The following works in the sense that I don't get an error:
console.log(07);
// or in my case:
console.log(007);
Of course, it will not retain the '00' in the value itself, since that value is effectively 7.
The same goes for the following:
console.log(7.0);
// or in my case:
console.log(7.000);
JavaScript understands what I am doing, but in the end the actual value will be 7, which can be proven with the following:
const leadingValue = 007;
const trailingValue = 7.00;
console.log(leadingValue, trailingValue); // both are exactly 7
But what I find curious is the following: the moment I combine these two I get a syntax error:
// but not this:
console.log(007.000);
1) Can someone explain why this isn't working?
I'm trying to find a solution to store numbers/floats with the exact precision without using string.
2) Is there any way in JS/NodeJS or even TypeScript to do this without using strings?
What I currently want to do is to receive the input, scan for the format and store that as a separate property and then parse the incoming value since parseInt('007.000') does work. And when the user wants to get this value return it back to the user... in a string.. unfortunately.
1) 007.000 is a syntax error because 007 is an octal integer literal, to which you're then appending a floating point part. (Try console.log(010). This prints 8.)
2) Here's how you can achieve your formatting using Intl.NumberFormat...
var myformat = new Intl.NumberFormat('en-US', {
minimumIntegerDigits: 3,
minimumFractionDigits: 3
});
console.log(myformat.format(7)); // prints 007.000
Hi
You can use an aproach that uses string funtions .split .padStart and .padEnd
Search on MDN
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
Here you have an example:
const x = 12.1;
function formatNumber( unformatedNumber) {
const desiredDecimalPad = 3;
const desiredNonDecimalPad = 3;
const unformatedNumberString = unformatedNumber.toString();
const unformatedNumberArr = unformatedNumberString.split('.');
const decimalStartPadded = unformatedNumberArr[0].padStart(desiredDecimalPad, '0');
const nonDecimalEndPadded = unformatedNumberArr[1].padEnd(desiredNonDecimalPad, '0');
const formatedNumberString = decimalStartPadded + '.' + nonDecimalEndPadded;
return formatedNumberString;
}
console.log(formatNumber(x))

Why regExp has diff results in diff senarios?

Simply speaking, in either node.js or in the browser, run the code below:
const sep = '\\';
const regExpression = `/b\\${sep}|a\\${sep}/`;
const testCases = ['a\\abb\\abc','b\\'];
const regTest = new RegExp(regExpression);
console.log(`Result for ${testCases[0]} is ${regTest.test(testCases[0])}`)
console.log(`Result for ${testCases[1]} is ${regTest.test(testCases[1])}`)
Both of the outputs are false:
error
however, if I change to this:
const regExpression = `/c|b\\${sep}|a\\${sep}/`;
Both of the results will be true....why?
right
Another interesting thing is: The matching condition cannot be always the first, which takes '/c|b\${sep}|a\${sep}/' as an example, 'c' will NOT match.....
Is because of the regex itself.
const regExpression = "/test/";
const regTest = new RegExp(regExpression);
console.log(regTest); // Regex: //test//
console.log(regTest.test("test")) // false
console.log(regTest.test("/test/")) // true
In the first case /b\\\\|a\\\\/ -> regex -> //b\\|a\\//. The regex will try to find /b\\ or a\\/. So will fail in both values.
'a\\abb\\abc' => FALSE
'b\\' => FALSE
'a\\/abb\\abc' => TRUE (a\\/ coincidence)
'/b\\' => TRUE (/b\\ coincidence)
In the second case /c|b\\\\|a\\\\/ -> regex-> /c|b\\|a\\/. The regex will try to find /c or b\\ or a\\/.
'a\\abb\\abc' => TRUE (b\\ coincidence)
'b\\' => TRUE (b\\ coincidence)
So, in conclusion you could solve your problem with:
const regExpression = `b\\${sep}|a\\${sep}`;
This should try to find b\\ or a\\. I don't know if this is the case but remember the ^ and $ regex tokens too. You could make your tests in regex101.

split creation date into two string

Is it possible to split this string into two using css or another way?
<p>30/10/2018 16:10</p>
into
<p>30/10/2018</p>
<p>16:10</p>
because i have a string data from JSON API that return value like "30/10/2018 16:10" by using this code <p>{{creationDate}}</p>
but I needed it to display like this
30/10/2018
16:10
Did anyone get any idea for how to settle this case?
You can split the date with space character which will give you the the date in 0 index and the time in 1 index:
<p>{{creationDate.split(' ')[0]}}</p>
<p>{{creationDate.split(' ')[1]}}</p>
Use moment for date format
import moment from 'moment'
Vue.filter('formatDate', function(value) {
if (value) {
return moment(String(value)).format('MM/DD/YYYY')
}
}
Vue.filter('formatTime', function(value) {
if (value) {
return moment(String(value)).format('hh:mm')
}
}
<P>{{yourDateString | formatDate}}</P>
<P>{{yourDateString | formatTime}}</P>
You can use Javascript split function. Use space as separator.
Syntax: string.split(separator, limit)
Read more: https://www.w3schools.com/jsref/jsref_split.asp
let creationDate="30/10/2018 16:10";
creationDate=creationDate.split(' ');
const docum=document.getElementById("date");
docum.innerHTML='<p>'+creationDate[0]+'</p>'+'<p>'+creationDate[1]+'</p>';
<div id="date"></div>

Jest Equality Matcher For Strings That Disregards Whitespace

Jest's toEqual matcher takes whitespace into account when checking for equality. When formatting the expected value in tests it is impossible to do so in a way that matches a string containing newlines, tabs etc.
Does Jest offer a way to disregard whitespace when matching?
Note: I edited the question to make it more generic.
As #Timo says, the only way of doing this appears to be with a custom matcher. Here is one that compresses all whitespace down to a single space for readability based on Jest's toEqual matcher. It will deal with tabs, newlines etc. It will give you pretty output like the included Jest matchers:
//matchStringIgnoringWhiteSpace.js
import { replace, map, equals } from 'ramda';
import { matcherHint, printReceived, printExpected } from 'jest-matcher-utils';
import diff from 'jest-diff';
const replaceWhitespace = replace(/\s+/g, ` `);
const compressWhitespace = map(replaceWhitespace);
const name = `toEqualWithCompressedWhitespace`;
export default function (received, expected) {
const [
receivedWithCompresssedWhitespace,
expectedWithCompresssedWhitespace,
] = compressWhitespace([received, expected]);
const pass = equals(
receivedWithCompresssedWhitespace,
expectedWithCompresssedWhitespace
);
const message = pass
? () =>
`${matcherHint(`.not.${name}`)}\n\n` +
`Uncompressed expected value:\n` +
` ${printExpected(expected)}\n` +
`Expected value with compressed whitespace to not equal:\n` +
` ${printExpected(expectedWithCompresssedWhitespace)}\n` +
`Uncompressed received value:\n` +
` ${printReceived(received)}\n` +
`Received value with compressed whitespace:\n` +
` ${printReceived(receivedWithCompresssedWhitespace)}`
: () => {
const diffString = diff(
expectedWithCompresssedWhitespace,
receivedWithCompresssedWhitespace,
{
expand: this.expand,
}
);
return (
`${matcherHint(`.${name}`)}\n\n` +
`Uncompressed expected value:\n` +
` ${printExpected(expected)}\n` +
`Expected value with compressed whitespace to equal:\n` +
` ${printExpected(expectedWithCompresssedWhitespace)}\n` +
`Uncompressed received value:\n` +
` ${printReceived(received)}\n` +
`Received value with compressed whitespace:\n` +
` ${printReceived(receivedWithCompresssedWhitespace)}${
diffString ? `\n\nDifference:\n\n${diffString}` : ``
}`
);
};
return {
actual: received,
expected,
message,
name,
pass,
};
};
To register the custom matcher you need to add it to your setupTests files. First register setupTests in your jest.config.js using the setupFilesAfterEnv field:
setupFilesAfterEnv: `<rootDir>/path/to/setupTests.js`,
And then register the custom matcher on the expect object.
//setupTests.js
import toMatchStringIgnoringWhitespace from "<rootDir>/path/to/matchStringIgnoringWhiteSpace";
expect.extend({
toMatchStringIgnoringWhitespace: toMatchStringIgnoringWhitespace
});
If you are using TypeScript you will also want to add the typings to the expect object following the instructions here.
As far as I know, there is no way to achieve this with Jest out of the box.
However, it is pretty straightforward to write your own reusable matcher using expect.extend. Remove all whitespace from both strings, e.g. via str.replace(/\s/g, ''), and compare the strings.
While this is not a direct answer, you can also do:
mockedFunction.mock.calls[0] // To get array of arguments
// or
mockedFunction.mock.calls[0][0] // to get first argument and so on
And then compare with equality.

Is there any way to create mongodb like _id strings without mongodb?

I really like the format of the _ids generated by mongodb. Mostly because I can pull data like the date out of them client side. I'm planning to use another database but still want that type of _id for my document. How can I create these ids without using mongodb?
Thanks!
A very easy pseudo ObjectId generator in javascript:
const ObjectId = (m = Math, d = Date, h = 16, s = s => m.floor(s).toString(h)) =>
s(d.now() / 1000) + ' '.repeat(h).replace(/./g, () => s(m.random() * h))
Use the official MongoDB BSON lib in the client
I have a browser client that generates ObjectIds. I wanted to make sure that I employ the same ObjectId algorithm in the client as the one used in the server. MongoDB has js-bson which can be used to accomplish that.
If you are using javascript with node.
npm install --save bson
Using require statement
var ObjectID = require('bson').ObjectID;
var id = new ObjectID();
console.log(id.toString());
Using ES6 import statement
import { ObjectID } from 'bson';
const id = new ObjectID();
console.log(id.toString());
The library also lets you import using good old script tags but I have not tried this.
Object IDs are usually generated by the client, so any MongoDB driver would have code to generate them.
If you're looking for JavaScript, here's some code from the MongoDB Node.js driver:
https://github.com/mongodb/js-bson/blob/1.0-branch/lib/bson/objectid.js
And another, simpler solution:
https://github.com/justaprogrammer/ObjectId.js
Extending Rubin Stolk's and ChrisV's answer in a more readable syntax (KISS).
function objectId () {
return hex(Date.now() / 1000) +
' '.repeat(16).replace(/./g, () => hex(Math.random() * 16))
}
function hex (value) {
return Math.floor(value).toString(16)
}
export default objectId
ruben-stolk's answer is great, but deliberately opaque? Very slightly easier to pick apart is:
const ObjectId = (rnd = r16 => Math.floor(r16).toString(16)) =>
rnd(Date.now()/1000) + ' '.repeat(16).replace(/./g, () => rnd(Math.random()*16));
(actually in slightly fewer characters). Kudos though!
This is a simple function to generate a new objectId
newObjectId() {
const timestamp = Math.floor(new Date().getTime() / 1000).toString(16);
const objectId = timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, () => {
return Math.floor(Math.random() * 16).toString(16);
}).toLowerCase();
return objectId;
}
Here's a link! to a library to do that.
https://www.npmjs.com/package/mongo-object-reader
You can read and write hexadecimal strings.
const { createObjectID, readObjectID,isValidObjectID } = require('mongo-object-reader');
//Creates a new immutable `ObjectID` instance based on the current system time.
const ObjectID = createObjectID() //a valid 24 character `ObjectID` hex string.
//returns boolean
// input - a valid 24 character `ObjectID` hex string.
const isValid = isValidObjectID(ObjectID)
//returns an object with data
// input - a valid 24 character `ObjectID` hex string.
const objectData = readObjectID(ObjectID)
console.log(ObjectID) //ObjectID
console.log(isValid) // true
console.log(objectData) /*
{ ObjectID: '5e92d4be2ced3f58d92187f5',
timeStamp:
{ hex: '5e92d4be',
value: 1586681022,
createDate: 1970-01-19T08:44:41.022Z },
random: { hex: '2ced3f58d9', value: 192958912729 },
incrementValue: { hex: '2187f5', value: 2197493 } }
*/
There is a detailed specification here
http://www.mongodb.org/display/DOCS/Object+IDs
Which you can use to roll your own id strings

Categories

Resources