FirebaseError:使用无效数据调用函数 Query.where()。不支持的字段值:在进行 Karma 测试时未定义
Posted
技术标签:
【中文标题】FirebaseError:使用无效数据调用函数 Query.where()。不支持的字段值:在进行 Karma 测试时未定义【英文标题】:FirebaseError: Function Query.where() called with invalid data. Unsupported field value: undefined while doing Karma testing 【发布时间】:2021-12-16 10:10:26 【问题描述】:当我通过karma
和angular cli
中的jasmine测试应用程序时,出现了这个错误:
FirebaseError:使用无效数据调用函数 Query.where()。 不支持的字段值:未定义
我应该采取什么步骤来解决这个问题?它是在组件的spec.ts
文件中还是已经在项目的后端代码中?请注意,这是我第一次处理使用Firebase
的项目
task-settings.component.ts
import Component, OnInit from '@angular/core';
import Router from '@angular/router';
import Params, ActivatedRoute from '@angular/router';
import AngularFireAuth from '@angular/fire/auth';
import AuthService from 'src/app/services/auth.service';
import TaskService from 'src/app/services/task.service';
import switchMap from 'rxjs/operators';
import FormBuilder, Validators from '@angular/forms';
import ToastService from 'src/app/services/toast.service';
// modal dialog import
@Component(
selector: 'task-settings',
templateUrl: './task-settings.component.html',
styleUrls: ['./task-settings.component.css'],
)
export class TaskSettingsComponent implements OnInit
term!: string;
dateToday = new Date();
userData: any;
fsData: any;
id!: any;
taskData: any;
taskStatus: any = ['Pending', 'Completed'];
taskScopeArray!: string[];
newTaskScopeArray!: string[];
addTaskForm!: any;
newTaskForm!: any;
taskRecipients:
uid: any;
status: string;
section: any;
submissionLink: string;
displayName: any;
[] = [];
userPushTokens: pushToken: string [] = [];
addTaskModal!: boolean;
addScopeModal!: boolean;
editTaskScope!: any;
verifyTasks$: any;
deleteTaskForm!: any;
deleteTaskModal!: boolean;
updateTaskForm!: any;
updateTaskConfirm!: boolean;
// editTaskScope! : any;
// end of edit task import
constructor(
public auth: AuthService,
private route: ActivatedRoute,
private router: Router,
readonly fire: AngularFireAuth,
private taskService: TaskService,
private fb: FormBuilder,
public toastService: ToastService
)
ngOnInit(): void
var d = new Date();
var y = d.getFullYear();
var n = d.getMonth();
console.log(n);
console.log(y);
if (n >= 1 && n <= 6)
console.log('January to June');
console.log('2nd Term SY ' + y + '-' + (y + 1));
this.term = '2nd Term SY ' + y + '-' + (y + 1);
else if (n >= 8 && n <= 12)
console.log('August to December');
console.log('1st Term SY ' + y + '-' + (y + 1));
this.term = '1st Term SY ' + y + '-' + (y + 1);
else
console.log('Summer Term' + y + '-' + (y + 1));
this.term = 'Summer Term' + y + '-' + (y + 1);
this.updateTaskForm = this.fb.group(
title: ['', Validators.required],
description: ['', Validators.required],
deadline: ['', Validators.required],
);
this.fire.user.subscribe((user: any) =>
this.userData = user;
this.auth.getUserData(user?.uid).subscribe((res) =>
this.fsData = res;
);
);
this.route.params
.pipe(
switchMap((params: Params) =>
console.log(params['id']);
return this.taskService.getTask(params['id']);
)
)
.subscribe((res) =>
this.updateTaskForm.controls.title.setValue(res.title);
this.updateTaskForm.controls.description.setValue(res.description);
this.updateTaskForm.controls.deadline.setValue(res.deadline);
this.taskData = res;
console.log(res);
);
this.taskScopeArray = [];
public triggerDeleteTaskModal()
this.deleteTaskModal = !this.deleteTaskModal;
public triggerUpdateTask()
this.updateTaskForm.controls.title.setValue(this.taskData.title);
this.updateTaskForm.controls.description.setValue(
this.taskData.description
);
this.updateTaskForm.controls.deadline.setValue(this.taskData.deadline);
public updateTask()
if (this.updateTaskForm.valid)
this.taskService.updateTask(
this.taskData.recipients,
this.taskData.taskId,
this.updateTaskForm.controls['title'].value,
this.updateTaskForm.controls['description'].value,
new Date (this.updateTaskForm.controls['deadline'].value),
).then(() => this.triggerUpdateTask())
.finally(() => this.updateTaskForm.reset())
else if (this.updateTaskForm.invalid)
this.updateTaskForm.controls['title'].markAsTouched();
this.updateTaskForm.controls['description'].markAsTouched();
this.updateTaskForm.controls['deadline'].markAsTouched();
this.toastService.publish("Please fillup all the requirements","formSuccess");
changeTaskScope(e: any)
console.log(e.target.value);
console.log(typeof e.target.value);
public deleteTask()
this.taskService.deleteTask(this.taskData.taskId).then(() =>
this.router.navigate(['/dashboard']);
);
task-settings.component.spec.ts
import ComponentFixture, TestBed from '@angular/core/testing';
import Component, OnInit from '@angular/core';
import Router from '@angular/router';
import Params, ActivatedRoute from '@angular/router';
import AngularFireAuth from '@angular/fire/auth';
import AuthService from 'src/app/services/auth.service';
import TaskService from 'src/app/services/task.service';
import switchMap from 'rxjs/operators';
import FormBuilder, FormsModule, ReactiveFormsModule, Validators from '@angular/forms';
import ToastService from 'src/app/services/toast.service';
import TaskSettingsComponent from './task-settings.component';
import RouterTestingModule from '@angular/router/testing';
import AngularFireModule from '@angular/fire';
import environment from 'src/environments/environment';
import AngularFireDatabaseModule from '@angular/fire/database';
import HttpClientModule from '@angular/common/http';
describe('TaskSettingsComponent', () =>
let component: TaskSettingsComponent;
let fixture: ComponentFixture<TaskSettingsComponent>;
beforeEach(async () =>
await TestBed.configureTestingModule(
declarations: [ TaskSettingsComponent ],
imports: [ RouterTestingModule, AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, HttpClientModule, ReactiveFormsModule, FormsModule ],
providers: [ AuthService, TaskService, ToastService ]
)
.compileComponents();
);
beforeEach(() =>
fixture = TestBed.createComponent(TaskSettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
);
it('should create', () =>
expect(component).toBeTruthy();
);
);
app.module.ts
import NgModule from '@angular/core';
import BrowserModule from '@angular/platform-browser';
import AngularFireModule from "@angular/fire";
import AngularFirestoreModule from "@angular/fire/firestore";
import AngularFireAuthModule from '@angular/fire/auth';
import AngularFireStorageModule from '@angular/fire/storage';
import AppRoutingModule from './app-routing.module';
import AppComponent from './app.component';
import DashboardComponent from '../app/dashboard-components/dashboard/dashboard.component'
import LoginComponent from './auth-components/login/login.component';
import PagenotfoundComponent from './pagenotfound/pagenotfound.component';
import ForgotPasswordComponent from './auth-components/forgot-password/forgot-password.component';
import environment from "src/environments/environment";
import FormsModule from '@angular/forms';
import ReactiveFormsModule from '@angular/forms';
import NavbarComponent from './navbar/navbar.component';
import MyProfileComponent from './my-profile-components/my-profile/my-profile.component';
import UserManagementComponent from './user-management-components/user-management/user-management.component';
import NgxPaginationModule from 'ngx-pagination'; // <-- import the module
import AngularFireFunctionsModule from '@angular/fire/functions';
import HttpClientModule from '@angular/common/http';
import UserComponent from './user-management-components/user/user.component';
import TaskComponent from './dashboard-components/task/task.component';
import TaskSettingsComponent from './dashboard-components/task-settings/task-settings.component';
import ReportComponent from './dashboard-components/report/report.component';
import ChartModule from 'angular2-chartjs';
import Ng2SearchPipeModule from 'ng2-search-filter';
import VerifyTaskComponent from './user-management-components/verify-task/verify-task.component';
import UserManualComponent from './user-manual/user-manual.component';
import ArchiveComponent from './archive/archive.component';
import AngularFireDatabaseModule from '@angular/fire/database';
@NgModule(
declarations: [
AppComponent,
DashboardComponent,
LoginComponent,
PagenotfoundComponent,
ForgotPasswordComponent,
NavbarComponent,
MyProfileComponent,
UserManagementComponent,
UserComponent,
TaskComponent,
TaskSettingsComponent,
ReportComponent,
VerifyTaskComponent,
UserManualComponent,
ArchiveComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
ChartModule,
AngularFireAuthModule,
ReactiveFormsModule,
NgxPaginationModule,
AngularFirestoreModule, //Firebase imports
AngularFireFunctionsModule,
AngularFireStorageModule,
Ng2SearchPipeModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireDatabaseModule
],
providers: [],
bootstrap: [AppComponent]
)
export class AppModule
task.service.ts
public setRecipients(scope:string):Observable<any>
return this.afs.collection('users',ref => ref.where('section','==',scope))
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return doc.map(
(c: payload: doc: data: () => any; id: any; ; ; ) =>
const data = c.payload.doc.data();
const id = c.payload.doc.id;
return id, ...data ;
))
);
public getTask(id:string):Observable<any>
return this.afs.collection('tasks',ref => ref.where('taskId','==',id))
.doc(id)
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return id: doc.payload.id, ...doc.payload.data() ;
)
);
public getCompletedTask(): Observable<any>
return this.afs
.collection('tasks', (ref) =>
ref.where('status', '==', 'Completed').orderBy('createdAt')
)
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return doc.map(
(c: payload: doc: data: () => any; id: any ) =>
const data = c.payload.doc.data();
const id = c.payload.doc.id;
return id, ...data ;
);
)
);
user.service.ts
public getDeptHeadUsers():Observable<any>
return this.afs.collection('users', ref => ref.where('role','==','Department Head').orderBy('createdAt','desc'))
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return doc.map(
(c: payload: doc: data: () => any; id: any; ; ; ) =>
const data = c.payload.doc.data();
const id = c.payload.doc.id;
return id, ...data ;
))
);
public getStudentUsers():Observable<any>
return this.afs.collection('users', ref => ref.where('role','==','Student',).orderBy('createdAt','desc'))
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return doc.map(
(c: payload: doc: data: () => any; id: any; ; ; ) =>
const data = c.payload.doc.data();
const id = c.payload.doc.id;
return id, ...data ;
))
);
public getAdminUsers():Observable<any>
return this.afs.collection('users', ref => ref.where('role','==','CICS Office Staff').orderBy('createdAt','desc'))
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return doc.map(
(c: payload: doc: data: () => any; id: any; ; ; ) =>
const data = c.payload.doc.data();
const id = c.payload.doc.id;
return id, ...data ;
))
);
auth.service.ts
import Injectable from '@angular/core';
import AngularFireAuth from '@angular/fire/auth';
import AngularFirestore from '@angular/fire/firestore';
import AngularFireFunctions from '@angular/fire/functions';
import Observable from 'rxjs';
import map from 'rxjs/operators';
import Router from '@angular/router';
import ToastService from './toast.service';
@Injectable(
providedIn: 'root'
)
export class AuthService
constructor(
private afs: AngularFirestore,
private fns: AngularFireFunctions,
readonly fire: AngularFireAuth,
public router: Router,
public toastService: ToastService
)
this.fire.authState.subscribe(user =>
if (user)
this.getUserData(user.uid).subscribe(res =>
if (res.role != 'CICS Office Staff' && res.role != 'Department Head')
this.signOut().then(() =>
this.toastService.publish('You are not allowed to access the web system. Please use the mobile application.','userDoesNotExist');
)
else if (res.role == 'CICS Office Staff' || res.role == 'Department Head')
console.log('Authenticated')
)
else
console.log('logged out');
)
public signup(email:string, password:string,displayName:string,contactNumber:string)
return this.fire.createUserWithEmailAndPassword(email, password)
// Update the user info with the given name
.then(res=>
res.user?.updateProfile(displayName: displayName)
.then(() =>
const data =
uid: res.user?.uid,
contactNumber: contactNumber,
email: email,
displayName: displayName,
createdAt: Date.now(),
role: 'CICS Office Staff'
this.afs.collection('users')
.doc(res.user?.uid).set(data)
.catch(error => console.log(error));
)
.then(() => res.user,console.log(res.user))
)
public signOut(): Promise<void>
console.log('Signing-out');
//this.guard.prompt('signIn').then(user => )
return this.fire.signOut()
.then(() => this.router.navigate(['/login']))
public signIn(email: string, password: string)
return this.fire.setPersistence('local').then(()=>
this.fire.signInWithEmailAndPassword(email,password)
.then(a => console.log('logged in!'))
.then(a => this.router.navigate(['/dashboard']))
.catch((err) =>
this.toastService.publish('The credentials you have entered does not match any user in our database','userDoesNotExist');
)
)
public getUserData(id:string):Observable<any>
return this.afs.collection('users')
.doc(id)
.snapshotChanges()
.pipe(
map((doc: any) =>
// console.log(doc)
return id: doc.payload.id, ...doc.payload.data() ;
)
);
public sendPasswordReset(email: string)
return this.fire.sendPasswordResetEmail(email).then(res => console.log(res), this.toastService.publish('Email has been sent to ' + email,'formSuccess')).catch((err) =>
this.toastService.publish('The credentials you have entered does not match any user in our database','userDoesNotExist');)
//firstName:string,lastName:string,email:string,contactNumber:string
public changeEmail(currentEmail:string, newEmail:string, password:string,id:string): Promise<any>
return this.fire.signInWithEmailAndPassword(currentEmail,password).then((res) =>
res.user?.updateEmail(newEmail).then(() =>
this.afs.collection('users').doc(id).set(
email: newEmail
, merge: true ) )
.catch(() =>
this.toastService.publish('The email ' + newEmail + ' is already registered in our database!','userDoesNotExist')
)
)
.then(() => this.toastService.publish('Your email has been updated to ' + newEmail,'formSuccess'))
.catch(() => this.toastService.publish('The credentials you have entered does not match any user in our database','userDoesNotExist'))
public editMyProfile(displayName:string, contactNumber:string, currentEmail:string, password:string,id:string): Promise<any>
return this.fire.signInWithEmailAndPassword(currentEmail,password).then((res) =>
res.user?.updateProfile(displayName: displayName)
).then(() =>
this.afs.collection('users').doc(id).set(
contactNumber: contactNumber,
displayName: displayName,
, merge: true )
)
.then(() => this.toastService.publish('Your profile has been updated','formSuccess'))
.catch(() => this.toastService.publish('The password you have entered is incorrect','userDoesNotExist'))
public deleteMyProfile(email:string,password:string,id:string): Promise<any>
return this.fire.signInWithEmailAndPassword(email,password).then((res) =>
this.afs.collection('users').doc(res.user?.uid).delete()
.then(() =>
res.user?.delete()
)
.then(() =>
this.router.navigate(['/login'])
)
.then(() =>
this.toastService.publish('Your account with the credentials ' + email + " has been deleted from our system",'userDoesNotExist')
)
).catch(() =>
this.toastService.publish('The credentials you have entered does not match any user in our database','userDoesNotExist');
)
public changeMyPassword(email:string, oldPassword:string, newPassword:string): Promise<any>
return this.fire.signInWithEmailAndPassword(email,oldPassword).then((res) =>
res.user?.updatePassword(newPassword)
.then(() =>
this.toastService.publish('Your password has been updated','formSuccess')
)
).catch(() =>
this.toastService.publish('The credentials you have entered does not match any user in our database','userDoesNotExist');
)
【问题讨论】:
【参考方案1】:此错误通常是由于您的查询接收到null
或undefined
参数值,这可能来自您的应用程序而不是checking for null values 在执行查询之前,或者应用程序在查询之前没有等待authentication to be completed火库。查看您的代码,我会检查 AuthService
和 TaskService
模块,因为它们似乎处理查询和身份验证。
该文档提供了一个page,它解释了如何在继续或设置将用于查询的值之前侦听身份验证状态更改:
import getAuth, onAuthStateChanged from "firebase/auth";
const auth = getAuth();
onAuthStateChanged(auth, (user) =>
if (user)
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = user.uid;
// ...
else
// User is signed out
// ...
);
否则,您可以共享处理查询的模块,以详细了解查询是如何执行的,以及身份验证是如何发生的。
【讨论】:
你好,我已经添加了处理查询的模块 查看您的task
和auth
服务模块后,来自此answer 的建议可能会阻止此错误出现,因为您的查询正在接收未定义的数据。至于为什么数据首先是undefined
,这似乎并不清楚。除了可以帮助设置测试环境的其他测试repository 之外,AngularFire repository 确实包含一个示例测试应用程序。
但问题是,auth
服务并没有真正的.where()
功能,只有在task
和user
服务模块中,我该如何应用更改那些服务模块?以上是关于FirebaseError:使用无效数据调用函数 Query.where()。不支持的字段值:在进行 Karma 测试时未定义的主要内容,如果未能解决你的问题,请参考以下文章
FirebaseError:使用无效数据调用函数 Query.where()。不支持的字段值:在进行 Karma 测试时未定义
未捕获的 FirebaseError:使用无效数据调用的函数 DocumentReference.set()。不支持的字段值:未定义
如何使用 Cordova 将动态数据从表单传递到 Firestore?
Flutter, FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - 调用 Firebase App.ini
FirebaseError:Firebase:未创建 Firebase 应用“[DEFAULT]” - 调用 Firebase App.initializeApp() (app/no-app)。 颤动