TypeError: Cannot read properties of undefined (reading 'text') in reguards to - fetch

okay, so I'm implementing fetch-node. I tried the example given in the docs
import fetch from 'fetch-node';
const response = await fetch('https://github.com/' );
const body = await response.text();
console.log(body);
got a lovely error:
TypeError: Cannot read properties of undefined (reading 'render')
❯ module.exports node_modules/hooks-node/hooks-node.js:8:11
❯ Proxy.module.exports node_modules/fetch-node/fetch-node.js:17:1
❯ tests/first.test.ts:4:29
1| import fetch from 'fetch-node';
2|
3| const response = await fetch('https://github.com/' );
| ^
4| const body = await response.text();
5|
next read more of the doc, and tried:
import fetch from 'fetch-node';
const response = await fetch('https://github.com/', {method: 'GET'} );
const body = await response.text();
console.log(body);
this resulted in:
❯ tests/first.test.ts:5:28
TypeError: Cannot read properties of undefined (reading 'text')
2|
3| const response = await fetch('https://github.com/', {method: 'GET'} );
4| const body = await response.text();
| ^
5|
6| console.log(body);
okay, so (1) Am I correctly using {method (2) what isn't the .text() method working on the response?

Related

NextJS Jest SyntaxError: Unexpected token 'export'

I'm trying to test a page in NextJs that has a firebase context provider that initializes firebase and another that controls access to firebase/auth. In the Auth Context I import things I need directly, like so:
import {
getAuth,
User,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
UserCredential,
signOut,
signInWithPopup,
GoogleAuthProvider,
} from "firebase/auth";
But Jest doesn't seem to like it, because I get this error:
SyntaxError: Unexpected token 'export'
15 | createUserWithEmailAndPassword,
16 | UserCredential,
> 17 | signOut,
| ^
18 | signInWithPopup,
19 | GoogleAuthProvider,
20 | } from "firebase/auth";
I do have ts-jest installed, and I saw a fix somewhere using babel but I'm not too fond of using babel with NextJS, is there another way to fix this issue?
You could use next-firebase-auth
it also shows how to set your app for jest:
// Create a mock FirebaseUser instance with the fields that you use.
const mockFirebaseUser = {
displayName: 'Banana Manana',
// ... other fields from firebaseUser that you may use
}
/**
* Build and return a dummy AuthUser instance to use in tests.
*
* #arg {boolean} isLoggedIn - Pass `false` to mimic a logged out user.
* #returns {AuthUserContext} - A mocked AuthUser instance, with 'serialize' added.
*/
const getMockAuthUser = (isLoggedIn = true) => ({
id: isLoggedIn ? 'abcd1234' : null,
email: isLoggedIn ? 'banana#banana.com' : null,
emailVerified: isLoggedIn,
getIdToken: jest.fn(async () => (isLoggedIn ? 'i_am_a_token' : null)),
clientInitialized: isLoggedIn,
firebaseUser: isLoggedIn ? mockFirebaseUser : null,
signOut: jest.fn(),
serialize: jest.fn(() => 'serialized_auth_user'),
})
export default getMockAuthUser

AsyncQueue Failed to persist write: TypeError: Cannot read properties of undefined (reading 'toString')

I'm trying to write unit test for my Firestore rules.
It loosely based on https://github.com/firebase/quickstart-testing/blob/master/unit-test-security-rules/test/firestore.spec.js
and following https://firebase.google.com/docs/firestore/security/test-rules-emulator
It has 3 test cases 2 of them pass fine.
3rd test is that the user can't delete a document but deleteDoc seems to throw an error.
[2022-10-11T19:56:27.376Z] #firebase/firestore: Firestore (9.11.0): AsyncQueue Failed to persist write: TypeError: Cannot read properties of undefined (reading 'toString')
[2022-10-11T19:56:27.377Z] #firebase/firestore: Firestore (9.11.0): INTERNAL UNHANDLED ERROR: TypeError: Cannot read properties of undefined (reading 'toString')
at ObjectMap.mapKeyFn (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/model/collections.ts:86:16)
at ObjectMap.get (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/util/obj_map.ts:49:21)
at ObjectMap.has (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/util/obj_map.ts:63:17)
at /Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/local_documents_view.ts:190:21
at /Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/util/sorted_map.ts:141:7
at LLRBNode.inorderTraversal (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/util/sorted_map.ts:324:7)
at SortedMap.inorderTraversal (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/util/sorted_map.ts:136:42)
at SortedMap.forEach (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/util/sorted_map.ts:140:10)
at LocalDocumentsView.populateOverlays (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/local_documents_view.ts:189:10)
at LocalDocumentsView.getOverlayedDocuments (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/local_documents_view.ts:174:17)
at /Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/local_store_impl.ts:350:48
at /Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/persistence_promise.ts:136:42
at PersistencePromise.wrapUserFunction (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/persistence_promise.ts:120:22)
at PersistencePromise.wrapSuccess (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/persistence_promise.ts:136:19)
at PersistencePromise.next (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/persistence_promise.ts:94:21)
at /Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/local_store_impl.ts:346:10
at MemoryPersistence.runTransaction (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/memory_persistence.ts:175:12)
at localStoreWriteLocally (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/local/local_store_impl.ts:327:6)
at syncEngineWrite (/Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/core/sync_engine_impl.ts:462:26)
at /Users/gustek/my-github/db-unit-tests-example/functions/node_modules/#firebase/firestore/src/core/firestore_client.ts:455:12
at processTicksAndRejections (node:internal/process/task_queues:96:5)
This is my test code
import {assertFails, assertSucceeds} from "#firebase/rules-unit-testing";
import firebase = require("#firebase/rules-unit-testing");
import fs = require("fs");
import {setDoc, deleteDoc} from "firebase/firestore";
const PROJECT_ID = "firestore-emulator-example";
describe("Rules test", function() {
let env: firebase.RulesTestEnvironment;
before(async () => {
// Load the rules file before the tests begin
const rules = fs.readFileSync("../firestore.rules", "utf8");
env = await firebase.initializeTestEnvironment(
{
projectId: PROJECT_ID,
firestore: {rules},
}
);
});
beforeEach(async () => {
// Clear the database between tests
await env.clearFirestore();
});
it("require users to log in before creating a profile", async () => {
const userId = "alice";
const context = env.authenticatedContext(userId);
await assertSucceeds(
setDoc(
context.firestore().doc(`/privateProfiles/${userId}`),
{}
)
);
});
it("edit only your own profile", async () => {
const alice = "alice";
const bob = "bob";
const aliceContext = env.authenticatedContext(alice);
const bobContext = env.authenticatedContext(bob);
await assertSucceeds(
setDoc(
aliceContext.firestore().doc(`/privateProfiles/${alice}`),
{}
)
);
await assertFails(
setDoc(
bobContext.firestore().doc(`/privateProfiles/${alice}`),
{}
)
);
});
it("can't directly delete a profile", async () => {
const alice = "alice";
const aliceContext = env.authenticatedContext(alice);
const db = aliceContext.firestore();
await assertSucceeds(
setDoc(
db.doc(`/privateProfiles/${alice}`),
{"smth": 1}
)
);
await assertFails(
deleteDoc(
db.doc(`/privateProfiles/${alice}`)
)
);
});
});
and full code at https://github.com/GustekDev/db-unit-tests-example
running the tests using firebase emulators:exec ./test.sh from inside functions directory.
Am I doing something wrong, or is that a bug in the Firebase?
The issue was resolved by changing
assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... })
to
assertSucceeds(setDoc(doc(alice.firestore(), '/users/alice'), { ... }))

Cannot call Firestore from Cloud Functions unit tests

Developing Google cloud functions locally.
Trying to test functions that invoke Firestore.
Here is a minimal example.
Emulators are running.
The function addMessage() works completely fine when invoked from the browser.
The function fails with error TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. when invoked from tests.
Question: Why is this error occurring and how can I invoke the Firestore function successfully from the tests?
functions/index.js:
require ('dotenv').config();
const functions = require ('firebase-functions');
const admin = require ('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest (async (req, res) => {
const original = req.query.text;
const writeResult = await admin.firestore().collection ('messages').add ({text: original});
const docSnap = await writeResult.get();
const writtenText = docSnap.get ('text');
res.send (`Message with text: ${writtenText} added.`);
});
functions/test/index.test.js:
const admin = require ('firebase-admin');
const firebase_functions_test = require ('firebase-functions-test')({
projectId: 'my-project-id'
}, '/path/to/google-application-credentials.json');
const testFunctions = require ('../index.js');
describe ('addMessage()', () => {
it ('returns Message with text: Howdy added.', (done) => {
const req = {query: {text: 'Howdy'} };
const res = {
send: (body) => {
expect (body).toBe (`Message with text: Howdy added.`);
done();
}
};
testFunctions.addMessage (req, res);
});
});
Starting jest from functions folder:
(Among other test-related output):
FAIL test/index.test.js
● addMessage() › returns Message with text: Howdy added.
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object
7 | exports.addMessage = functions.https.onRequest (async (req, res) => {
8 | const original = req.query.text;
> 9 | const writeResult = await admin.firestore().collection ('messages').add ({text: original});
| ^
10 | const docSnap = await writeResult.get();
11 | const writtenText = docSnap.get ('text');
12 | res.send (`Message with text: ${writtenText} added.`);
at GrpcClient.loadProto (node_modules/google-gax/src/grpc.ts:166:23)
at new FirestoreClient (node_modules/#google-cloud/firestore/build/src/v1/firestore_client.js:118:38)
at ClientPool.Firestore._clientPool.pool_1.ClientPool [as clientFactory] (node_modules/#google-cloud/firestore/build/src/index.js:326:26)
at ClientPool.acquire (node_modules/#google-cloud/firestore/build/src/pool.js:87:35)
at ClientPool.run (node_modules/#google-cloud/firestore/build/src/pool.js:164:29)
at Firestore.request (node_modules/#google-cloud/firestore/build/src/index.js:983:33)
at WriteBatch.commit_ (node_modules/#google-cloud/firestore/build/src/write-batch.js:496:48)
Caused by: Error:
at WriteBatch.commit (node_modules/#google-cloud/firestore/build/src/write-batch.js:415:23)
at DocumentReference.create (node_modules/#google-cloud/firestore/build/src/reference.js:283:14)
at CollectionReference.add (node_modules/#google-cloud/firestore/build/src/reference.js:2011:28)
at Object.<anonymous>.exports.addMessage.functions.https.onRequest (index.js:9:71)
at Object.addMessage (node_modules/firebase-functions/lib/providers/https.js:50:16)
at Object.done (test/index.test.js:17:19)
Environment:
"node": "10"
"firebase-admin": "^8.12.1",
"firebase-functions": "^3.7.0"
"firebase-functions-test": "^0.2.1",
"jest": "^25.5.4"
Solved by adding jest.config.js to functions/:
module.exports = {
testEnvironment: 'node'
};
Solution based on this (but NB I needed to place jest.config.js in functions/, not the project root).
Also tried this but appeared to do nothing.
Tests now run perfectly except that they end with a Jest error:
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.
This seems to be harmless.
Thanks #gso_gabriel for the valuable links!

Implement requestHooks in cucumber/testCafe

When I want to add requestHooks (for example) to my test and fixture I basically don't know where to do it.
I am using this repo https://github.com/rquellh/testcafe-cucumber
I find a solution. however, it is not stable: sometimes it throws an error: '[object DOMException]:\n No stack trace available'. Maybe someone knows why?
The code ( after creat mock and logger object as in testCafe doc):
When('I log in as free user', async () => {
await testController.addRequestHooks(mock)
await testController.addRequestHooks(logger)
await testController.wait(2000)
await testController
.click(selector)
.typeText(selector,string, {replace : true})
.typeText(selector,string, {replace: true})
.click(selector);
});
UPDATE: now it works with wait() function, but maybe there is some more elegant answer for that?
testController is available in Given, When, Then steps.
So, you can use the test controller standard methods: addRequestHooks and removeRequestHooks.
I've modified the example from the https://github.com/rquellh/testcafe-cucumber repository to demonstrate the RequestLogger usage.
const {Given, When, Then} = require('cucumber');
const Role = require('testcafe').Role;
const RequestLogger = require('testcafe').RequestLogger;
const githubPage = require('../support/pages/github-page');
const logger = new RequestLogger('https://github.com');
Given(/^I open the GitHub page$/, async function() {
await testController.addRequestHooks(logger);
await testController.navigateTo(githubPage.github.url());
});
...
Then(/^Logger should contain captured request information$/, async function() {
await testController.expect(logger.contains(record => record.response.statusCode === 200)).ok();
});
...
My solution (gherkin-testcafe: ^2.2.0):
The definition:
Feature: Check server names
Scenario Outline: Fetch pages
Given there is the <url>
When I check the response status
Then the http <prameter> equals the <value>
Examples:
| url | prameter | value |
| https://www.seznam.cz | server | nginx |
| https://www.google.com | server | gws |
And the implementation:
const {Given, When, Then} = require('cucumber');
const {RequestLogger} = require('testcafe');
let logger;
Given(/there is the (.+)/, async (t, [url]) => {
logger = RequestLogger(url, {
logResponseHeaders: true,
});
await t.addRequestHooks(logger);
await t.navigateTo(url);
});
When(/I check the response status/, async t => {
await t.expect(logger.contains(record => record.response.statusCode === 200)).ok();
});
Then(/the http (.+) equals the (.+)/, async (t, [name, value]) => {
await t.expect(logger.contains(record => record.response.headers.server === value)).ok();
});

Expert wanted AngularFire2 firestore nested collection get data?

Hey I couldn't find how can i do nested query in firestore ?
this.match1 = this.MatchCollection1.snapshotChanges().pipe(map(actions => {
return actions.map(a => {
const data = a.payload.doc.data() as Matches;
const uid = data.pairer;
const id = a.payload.doc.id;
const photourl = afs.collection(`users/${uid}/photos`,
ref => ref.where('index', '==', 0).where('deleted', '==', false)).snapshotChanges().pipe(map(action => {
return action.map(p => {
const pdata = p.payload.doc.data() as Photos;
return pdata.url;
});
}));
return {id, uid, url: photourl, ...data};
});
}));
My problem photourl return observable how can i do return object like others
A bit tricky to follow but I think all you need to do is move your return {id, uid, url: photourl, ...data}; From what I can see you are just missing a subscription to unpack your observable and extract the value. EG
return action.map(p => {
const pdata = p.payload.doc.data() as Photos;
return pdata.url;
});
})).subscribe(photo => {
"if you want to set photourl do it here photourl = photo.url;"
return photo; //do what you need to before you return the actual
photo object.
});
You can use toPromise method with async await.
Data structure
users
| userId1
| photos
| photoId1
| url : 'someURL'
| photoId2
| url : 'someURL2'
Service or component file
items;
getPhotos(uid){
return this.db.collection(`users/${uid}/photos`).valueChanges()
.pipe(first()).toPromise() // get first stream and return it as promise
}
async fooFunc() {
let user_id = 'userId1' //TODO: get user uid from somewhere
this.items = await this.getPhotos(user_id) // await getPhotos promise finish
console.log(this.items) // return [Object, Object]
}
component html template
<li *ngFor="let item of items">
{{ item | json }}
</li>
output
{ "url": "someURL" }
{ "url": "someURL2" }

Resources