FIRESTORE (7.14.3) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array
rodrigoehlers opened this issue · 15 comments
Describe your environment
- Operating System version: macOS Catalina Version 10.15.4
- Browser version: None
- Node.js version: 12.5.0
- Firebase SDK version: 7.14.4 (implicitly through latest
@firebase/testing
) - Firebase Testing SDK version: 0.19.4
- Firebase Product: firestore and testing
- Jest version: 26.0.1
Describe the problem
Steps to reproduce:
Use the code below, then run tests with jest <path-to-your-file>
. In my case <path-to-your-file>
was ./spec/basic.spec.js
.
It seems that firebase.assertFails(...)
throws an error and never returns. Jest doesn't exit.
You'll receive the following logs:
(node:18117) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
FAIL spec/basic.spec.js
Minimal test
✕ this tests throws an error and never returns (286 ms)
● Minimal test › this tests throws an error and never returns
FIRESTORE (7.14.3) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array
at fail (node_modules/@firebase/firestore/src/util/assert.ts:39:9)
at hardAssert (node_modules/@firebase/firestore/src/util/assert.ts:53:5)
at JsonProtoSerializer.fromBytes (node_modules/@firebase/firestore/src/remote/serializer.ts:250:7)
at JsonProtoSerializer.fromWatchChange (node_modules/@firebase/firestore/src/remote/serializer.ts:431:32)
at PersistentListenStream.onMessage (node_modules/@firebase/firestore/src/remote/persistent_stream.ts:568:41)
at node_modules/@firebase/firestore/src/remote/persistent_stream.ts:448:21
at node_modules/@firebase/firestore/src/remote/persistent_stream.ts:501:18
at node_modules/@firebase/firestore/src/util/async_queue.ts:358:14
console.error
[2020-05-21T14:11:50.900Z] @firebase/firestore: Firestore (7.14.3): FIRESTORE (7.14.3) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array
at Logger.defaultLogHandler [as _logHandler] (node_modules/@firebase/logger/src/logger.ts:115:57)
at Logger.error (node_modules/@firebase/logger/src/logger.ts:203:21)
at logError (node_modules/@firebase/firestore/src/util/log.ts:45:20)
at fail (node_modules/@firebase/firestore/src/util/assert.ts:34:3)
at hardAssert (node_modules/@firebase/firestore/src/util/assert.ts:53:5)
at JsonProtoSerializer.fromBytes (node_modules/@firebase/firestore/src/remote/serializer.ts:250:7)
at JsonProtoSerializer.fromWatchChange (node_modules/@firebase/firestore/src/remote/serializer.ts:431:32)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 2.203 s
Ran all test suites matching /.\/spec\/basic.spec.js/i.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
Relevant Code:
Use the following as firestore.rules
:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if false;
allow write: if false;
}
}
}
Create a minimal test, reading from a collection:
const firebase = require('@firebase/testing');
describe('Minimal test', () => {
const projectId = 'project-id';
let db;
let ref;
beforeAll(() => {
db = firebase.initializeTestApp({ projectId }).firestore();
ref = db.collection('hello-world');
});
afterAll(() => Promise.all(firebase.apps().map((app) => app.delete())));
test('this tests throws an error and never returns', async () => {
await expect(await firebase.assertFails(ref.get()));
});
});
What have I tried
Downgrading @firebase/testing
to version ^0.15.0
fixed the issue.
When I tested on my real rules and tests however, it seems to have broken the test reports as setValue
is not in const compressedTypes = ['mapValue', 'listValue', 'constraintValue']
in the repost .html
function
buildValueString(...)
yet? This is only speculation! It could be that my rules are simply wrong.
The report .html
therefore throws the following error a couple of times:
Found invalid expression-return type.
Someone with a similar issue posted on StackOverflow.
Thank you for reporting this issue. I was able to reproduce and created a GitHub repository with my reproduction steps: https://github.com/dconeybe/FirebaseJsBug3096. I will look into this and update this bug with my findings.
Just an update that I am still investigating. I have not found the root cause yet.
Seeing this also. Any workarounds?
The issue seems to be resolved with firebase version @7.14.6
and @firebase/testing version @0.19.6
. I just upgraded both, re-ran tests and all my tests passed without issues.
I'm still seeing this with
firebase-admin@8.12.1
@firebase/testing@0.19.6
jest@26.0.1
ts-jest@26.0.0
I'm also seeing this, but am using firebase directly not firebase-testing
firebase-admin@8.12.1
firebase@7.14.6
jest@26.0.1
ts-jest@26.0.0
I'm seeing this with firebase@7.14.6 and "@angular/fire": "^5.4.2","firebase-tools": "^7.12.1",
in my angular project
Update: Although my investigation is still in progress, here is what I have so far. It looks like this behavior may be due to a "bug" in Jest. The problem surfaces in the follow code from serializer.ts:
value === undefined || value instanceof Uint8Array
The value
object is an instance of Buffer, which is a subclass of Uint8Array
; however, the value instanceof Uint8Array
is mysteriously evaluating to false
, causing the assertion failure.
My hypothesis is that the Jest testing framework is doing something wonky with "realms", an advanced feature that allows for different global memory spaces for different parts of a JavaScript program. This has come up as an issue with Jest before, and there is a potential workaround: jestjs/jest#7780.
It looks like the workaround documented in jestjs/jest#7780 fixes the problem. I've updated my reproduction app, https://github.com/dconeybe/FirebaseJsBug3096, with the workaround steps and a workaround
branch to demonstrate it.
Since this issue does not appear to be a bug in the Firebase SDK, but rather a side effect of how Jest executes tests, I am going to close this ticket. Feel free to re-open, however, if you disagree and we can continue the discussion. If you think of it, please report back your success with this or other workarounds.
+1
Just came across this error with Jest as well and the workaround is perfect! Followed the workaround and all my tests worked perfectly without any problems.
For others having the same issue and referring to this, use @dconeybe's workaround and your tests should run without problems again.
Okay, so I'm not sure if this fix applies to other people or just me. But when I was designing my application, I was using Ng/Rx to manage state. I had actions, reducers, and effects designed around Firebase Auth state. I would store user info when a user was authenticated, but ALSO and here's the crucial mistake, I was also storing the credential object that gets passed in after angularFire auth login functions. To be specific I am talking about this credential object: https://firebase.google.com/docs/reference/js/firebase.auth.AuthCredential
Now, it took me 6 hours, I tried all sorts of different package versions, but I finally realized the cause of this error. What happens is if I tried to make or store a copy of the credential object values, it would always lead to all kinds of Internal Firebase errors with INTERNAL ASSERTION FAILED to be only one of them. After removing any code related to reading or writing the values that came from the credential object, the error went away completely.
TLDR; It looks like Firebase has some security code that causes errors when interacting with credential objects. Remove that and the Internal Assertion Failed goes away
Sorry to bring this up again but apparently this solution does not work once you convert your tests into Typescript.
I've tried converting the solution from Javascript into Typescript but it still displayed the error:
(node:2960) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 4)
console.error
[2020-06-07T03:58:48.724Z] @firebase/firestore: Firestore (7.14.5): FIRESTORE (7.14.5) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array
at Logger.defaultLogHandler [as _logHandler] (node_modules/@firebase/logger/src/logger.ts:115:57)
at Logger.error (node_modules/@firebase/logger/src/logger.ts:203:21)
at logError (node_modules/@firebase/firestore/src/util/log.ts:45:20)
at fail (node_modules/@firebase/firestore/src/util/assert.ts:34:3)
at hardAssert (node_modules/@firebase/firestore/src/util/assert.ts:53:5)
at JsonProtoSerializer.fromBytes (node_modules/@firebase/firestore/src/remote/serializer.ts:250:7)
at JsonProtoSerializer.fromWatchChange (node_modules/@firebase/firestore/src/remote/serializer.ts:431:32)
Is there something I'm missing? Because I'm pretty sure the solution provided above will work for Typescript but I'm not sure if we need to change some things up.
Edit: I've resolved this problem.
Solution
- Create a jest.config.js
- Paste in this code
module.exports = {
testEnvironment: "./__test-utils__/custom-jest-environment.js",
}
- Run your tests, it should work already.
@moscoso There's no special code for causing failures related to credential objects. So far the issue we've seen here had to do with Jest breaking globals in such a way that a value in the form of a Uint8Array
would not pass a value instanceof Uint8Array
test. The resolution discussed so far has been a workaround specific to Jest.
In your first post you listed a number of dependencies and versions but did not include Jest. Was that the complete set of dependencies you're using? If so, you might be experiencing a different issue. If you could post a minimal reproduction along the lines of dconeybe's, we can help you figure out what's going on.
@wilhuff my issue turned out to be completely separate from OP and not having to do with Jest... Maybe there is no special code for that, all I'm saying is that if you try to copy the credential object after a login method from AngularFire auth service, it will lead to INTERNAL ASSERTION FAILED.... I could re-create code if you really need me to, but it's exactly what I said. It's not longer an issue for me, removing the code that copies that credential object fixed it for me. Just letting people know if they stumble upon this thread because of the INTERNAL ASSERTION FAILED message
For those that need jest-environment-jsdom
instead of jest-environment-node
, I was able to get my tests working with a similar workaround:
- Add
jest-environment-jsdom
as a dev dependency inpackage.json
- Add
custom-jest-environment.js
containing the following:
'use strict';
/**
* Correct Jest bug that prevents the Firestore tests from running. More info here:
* https://github.com/firebase/firebase-js-sdk/issues/3096#issuecomment-637584185
*/
const BrowserEnvironment = require('jest-environment-jsdom');
class MyEnvironment extends BrowserEnvironment {
constructor(config) {
super(
Object.assign({}, config, {
globals: Object.assign({}, config.globals, {
Uint32Array: Uint32Array,
Uint8Array: Uint8Array,
ArrayBuffer: ArrayBuffer
})
})
);
}
async setup() {}
async teardown() {}
}
module.exports = MyEnvironment;
- Add the new custom environment to
jest.config.js
:
testEnvironment: './test/custom-jest-environment.js'