ethers.js
ethers.js copied to clipboard
`invalid BytesLike value` on `createRandom` in jest
Ethers Version
6.6.2
Search Terms
No response
Describe the Problem
Calling Wallet.createRandom()
in jest environment causes an error, the same thing applies to when I try to create a Wallet using a mnemonic phrase Wallet.fromPhrase(phrase)
Code Snippet
describe("evmTests", () => {
test("setup", async() => {
const w = Wallet.createRandom()
expect(1).toBe(1)
})
})
Contract ABI
No response
Errors
TypeError: invalid BytesLike value (argument="value", value={ "data": [ 136, 147, 113, 168, 255, 56, 15, 137, 131, 87, 45, 124, 173, 28, 199, 107, 61, 103, 192, 19, 159, 170, 93, 228, 76, 59, 243, 25, 29, 144, 63, 194 ], "type": "Buffer" }, code=INVALID_ARGUMENT, version=6.6.7)
Environment
No response
Environment (Other)
No response
Hey, i think i have a similar problem when using ethers.sha256
inside a test. Interestingly, this only happens when using the jsdom
test environment.
ethers.sha256('0x0001')
I suspect that this happens because the hexlify
method expects a BytesLike
:
but the _sha256
implementation returns a Buffer
:
From looking at the ethers code, I figured that i could register a slightly adjusted sha256
implementation as a workaround in my test setup. I am not sure if this has any unintended side-effects, so please use with caution:
// https://github.com/ethers-io/ethers.js/issues/4365#issuecomment-1721313836
ethers.sha256.register((data) => {
return new Uint8Array(crypto.createHash('sha256').update(data).digest());
});
A Buffer is a sub-class of Uint8Array though. Does Jest perhaps replace the Buffer class with its own? Can you try console.log(Buffer.from([]) instanceof Uint8Array)
?
@ricmoo I tried logging that in jest environment, it gives out false
@ricmoo I tried logging that in jest environment, it gives out
false
I can confirm that this is the case with testEnvironment: 'jsdom'
. It prints out true
if i remove the testEnvironment
configuration in my jest config.
I suspect that the jest-environment-jsdom
environment somehow changes the Buffer
or Uint8Array
implementation? Unfortunately I dont really have an idea how to debug this further.
Okay I investigated this a bit more and it seems like this is a known problem with jest and how it uses executions contexts: https://github.com/jestjs/jest/issues/2549, https://github.com/jestjs/jest/issues/7780#issuecomment-669828353, https://github.com/jestjs/jest/issues/14363#issuecomment-1651658124
As far as I understand, there are two sets of globals, one in the Node.js context and one in the Jest context. I suspect that this line in the jest-environment-jsdom
package sets the Buffer
from the Node.js context into the Jest context, but it does not do the same for Uint8Array
. The instanceof check then fails because the passed buffer instance extends the Uint8Array
from the Node.js context, but ethers checks against the Uint8Array
from the Jest context:
https://github.com/jestjs/jest/blob/81cc9f07e8f0c664f8664d22feab9bec2a226882/packages/jest-environment-jsdom/src/index.ts#L85
The problem does not appear when using jest-environment-node
(which is the default environment) because this environment also sets the Uint8Array
of the Jest context:
https://github.com/jestjs/jest/blob/81cc9f07e8f0c664f8664d22feab9bec2a226882/packages/jest-environment-node/src/index.ts#L134-L139
Okay but the test that I'm writing require jest-environment-jsdom
if someone has the same issue, yet. I was able to workaround it by:
- Creating a
jest.setup.ts
;
Object.defineProperty(Uint8Array, Symbol.hasInstance, {
value(potentialInstance: unknown) {
return this === Uint8Array
? Object.prototype.toString.call(potentialInstance) ===
'[object Uint8Array]'
: Uint8Array[Symbol.hasInstance].call(this, potentialInstance);
},
});
- Adding the setup to
jest.config.ts
on propsetupFilesAfterEnv
;
setupFilesAfterEnv: ['./jest.setup.ts'],
Oh wow. So, in Jest instanceof Uint8Array
doesn’t work??
Same error is also occurring while calling any contract call inside of Vitest
unit test suite.
Workaround is not to use environment: 'jsdom'
but instead environment: 'happy-dom'
inside of defineConfig({ test: { environment: '...',
Btw. This issue might be related with https://github.com/ethers-io/ethers.js/issues/4436