I find myself reaching to previous projects for this function every time I need a random, unique value to use on the client-side. You might not have heard of the Web Crypto API which provides a set of low-level primitives for dealing with cryptography. For a rather unpopular API, Web Crypto API is well supported in modern browsers and IE 11.
// random.ts
function randomId(): string {
const uint32 = window.crypto.getRandomValues(new Uint32Array(1))[0];
return uint32.toString(16);
}
There are multiple packages available that can fulfill a similar purpose, although this particular browser-native solution has a few advantages over packages like nanoid, shortid, or uuid. Using native Crypto module doesn't commit to the always-growing dependencies list in your project. The output is also short and easy to read. The last point becomes especially important if your users get to see the id and might be asked for it by your support (e.g., order number).
To test randomId in Node.js you want to go and mock Crypto.getRandomValues.
// setup.ts
import crypto from "crypto";
function getRandomValuesMock<
T extends
| Int8Array
| Int16Array
| Int32Array
| Uint8Array
| Uint16Array
| Uint32Array
| Uint8ClampedArray
| Float32Array
| Float64Array
| DataView
>(array: T) {
return crypto.randomFillSync(array);
}
global.crypto = { getRandomValues: getRandomValuesMock };
Testing random values can be tricky. In some use cases, you might require deterministic result and other instances you relay on a unique value across a series of function calls. That's why I wouldn't go for mocking the resulting value from the get-go.
// random.spec.ts
test("generates a pseudo-random id", () => {
expect(randomId()).toEqual(expect.any(String));
});
Wrap up
I hope you found this post useful and spare your users downloading some additional bytes. Keep in might that although getRandomValues offers cryptographically secure random values, it's still the client-side and you shouldn't rely on it for security-critical use cases.
Photo by Brett Jordan on Unsplash.