firestore规则测试总是以超时错误结束



我正在尝试测试我编写的firestore安全规则,但每次我试图运行我的测试时,我都得到超时错误。

在运行测试之前,我使用以下命令启动firestore模拟器:

❯ npm run firebase:run:emulator
> warzywniax@0.0.0 firebase:run:emulator
> cd firebase && firebase emulators:start --project=warzywniax --import=./seed --export-on-exit
i  emulators: Starting emulators: auth, firestore, storage
i  firestore: Importing data from /firebase/seed/firestore_export/firestore_export.overall_export_metadata
i  firestore: Firestore Emulator logging to firestore-debug.log
✔  firestore: Firestore Emulator UI websocket is running on 9150.
i  auth: Importing config from /firebase/seed/auth_export/config.json
i  auth: Importing accounts from /firebase/seed/auth_export/accounts.json
i  ui: Emulator UI logging to ui-debug.log
┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://127.0.0.1:4000/               │
└─────────────────────────────────────────────────────────────┘
┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ 127.0.0.1:9099 │ http://127.0.0.1:4000/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ 127.0.0.1:8080 │ http://127.0.0.1:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Storage        │ 127.0.0.1:9199 │ http://127.0.0.1:4000/storage   │
└────────────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at 127.0.0.1:4400
Other reserved ports: 4500, 9150

看起来一切正常。我的firestore模拟器托管在127.0.0.1:8080并且通过我的web浏览器访问这个模拟器没有任何问题。

在我运行任何测试之前,我在setupFilesAfterEnvjest hook上运行一些设置脚本。整个设置脚本如下所示:

import { initializeTestEnvironment, RulesTestEnvironment } from '@firebase/rules-unit-testing';
import firebase from 'firebase/compat/';
export let testEnvironment: RulesTestEnvironment;
export let guestUserContext: firebase.firestore.Firestore;
beforeAll(async () => {
testEnvironment = await initializeTestEnvironment({
firestore: {
host: '127.0.0.1',
port: 8080,
},
projectId: 'warzywniax',
});
guestUserContext = testEnvironment.unauthenticatedContext().firestore();
console.info('TEST_ENV is ready:n', testEnvironment);
console.info('GUEST_USER is ready:n', guestUserContext);
});

然后尝试运行一些简单的测试,像这样:

import { assertSucceeds } from '@firebase/rules-unit-testing';
import { guestUserContext } from '../integration-setup';
describe('Offers collection tests', () => {
it('should allow to read offers for any user', async () => {
const testQuery = guestUserContext.collection('offers');
expect(await assertSucceeds(testQuery.get()));
});
});

返回以下错误:

FAIL  test/integration/firebase/firestore.rules.spec.ts (5.234 s)
Offers collection tests
✕ should allow to read offers for any user (5001 ms)
● Offers collection tests › should allow to read offers for any user
thrown: "Exceeded timeout of 5000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout.

我已经检查了收集是否有任何问题,但如果我记录testQuery,它看起来很好。

我也按照上面错误的建议,将超时时间延长到30s (--testTimeout=30000)。什么产生了奇怪的结果。我的测试通过了,但还是出现了这样的错误:

console.error
[2023-03-30T15:45:44.552Z]  @firebase/firestore: Firestore (9.17.1): Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.
This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.
at Logger.defaultLogHandler [as _logHandler] (node_modules/@firebase/logger/src/logger.ts:115:57)
at Logger.Object.<anonymous>.Logger.error (node_modules/@firebase/logger/src/logger.ts:210:5)
at x (node_modules/@firebase/firestore/dist/index.esm2017.js:124:11)
at Pu.au (node_modules/@firebase/firestore/dist/index.esm2017.js:13778:20)
at nc.op (node_modules/@firebase/firestore/dist/index.esm2017.js:13748:14)
at node_modules/@firebase/firestore/dist/index.esm2017.js:14307:14
at node_modules/@firebase/firestore/dist/index.esm2017.js:17414:73
at node_modules/@firebase/firestore/dist/index.esm2017.js:17447:54
PASS  test/integration/firebase/firestore.rules.spec.ts (10.335 s)
Offers collection tests
✓ should allow to read offers for any user (10168 ms)

在我看来,什么应该使这个测试失败。你有什么想法可能是错误的,我该如何解决这个问题?

我遇到了这个问题。我有几个与Firebase规则相关的Jest测试,所有这些测试都由于超时而失败,而我所有的Firebase数据库规则测试都通过了。

经过大量的研究,我了解到的是,至少在我这边,这个问题与使用jsdom的测试环境有关。当我切换到Jest的默认测试环境,即node时,测试又开始通过了。

我找到的主要帮助是这个线程(原文如此)React native repo。https://github.com/facebook/react-native/issues/36342

整篇文章中最重要的一段是:这里的根本问题是RN的Jest环境现在只将react-native作为导出条件(而不是节点)导出,这意味着导出节点目标的包现在可能会以不同的方式解析。在firebase的情况下,它默认返回到ESM。老实说,这应该被标记为对Jest设置的突破性更改-抱歉。">

我希望这能帮助到别人。

我运行了您的设置,并且能够通过测试。检查这里的版本号,看看它是否是任何问题的原因。输出也可以以有意义的方式不同:

import { initializeTestEnvironment } from '@firebase/rules-unit-testing';
export let testEnvironment;
export let guestUserContext;
beforeEach(async () => {
testEnvironment = await initializeTestEnvironment({
firestore: {
host: '127.0.0.1',
port: 8080,
},
projectId: 'warzywniax',
});
guestUserContext = testEnvironment.unauthenticatedContext().firestore();
console.info('TEST_ENV is ready:n', testEnvironment);
console.info('GUEST_USER is ready:n', guestUserContext);
});
import { initializeTestEnvironment, assertSucceeds } from '@firebase/rules-unit-testing';
import { guestUserContext } from './lib.js';
describe('Offers collection tests', () => {
it('should allow to read offers for any user', async () => {
const testQuery = guestUserContext.collection('offers');
await assertSucceeds(testQuery.get());
});
});

node . js package.json:

{
"name": "rulestestingso",
"version": "1.0.0",
"description": "Testing this",
"main": "main.js",
"type": "module",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "chris",
"license": "ISC",
"dependencies": {
"@firebase/rules-unit-testing": "^2.0.7",
"firebase": "^9.19.0",
"jest": "^29.5.0"
}
}
$ mocha main.js

Offers collection tests
TEST_ENV is ready:
RulesTestEnvironmentImpl {
projectId: 'warzywniax',
emulators: { firestore: { host: '127.0.0.1', port: 8080 } },
contexts: Set(1) {
RulesTestContextImpl {
projectId: 'warzywniax',
emulators: [Object],
authToken: undefined,
destroyed: false,
envDestroyed: false,
app: [FirebaseAppImpl]
}
},
destroyed: false
}
GUEST_USER is ready:
Firestore {
_delegate: Firestore {
_authCredentials: FirebaseAuthCredentialsProvider {
authProvider: [Provider],
currentUser: [User],
tokenCounter: 0,
forceRefresh: false,
auth: null
},
_appCheckCredentials: FirebaseAppCheckTokenProvider {
appCheckProvider: [Provider],
forceRefresh: false,
appCheck: null,
latestAppCheckToken: null
},
_databaseId: DatabaseId { projectId: 'warzywniax', database: '(default)' },
_app: FirebaseAppImpl {
_isDeleted: false,
_options: [Object],
_config: [Object],
_name: '_Firebase_RulesUnitTesting_1680224130695_0.0042143144476949335',
_automaticDataCollectionEnabled: false,
_container: [ComponentContainer]
},
type: 'firestore',
_persistenceKey: '_Firebase_RulesUnitTesting_1680224130695_0.0042143144476949335',
_settings: FirestoreSettingsImpl {
host: '127.0.0.1:8080',
ssl: false,
credentials: undefined,
ignoreUndefinedProperties: false,
cache: undefined,
cacheSizeBytes: 41943040,
experimentalForceLongPolling: false,
experimentalAutoDetectLongPolling: false,
useFetchStreams: true
},
_settingsFrozen: false,
_queue: AsyncQueueImpl {
tail: [Promise],
retryableOps: [],
_isShuttingDown: false,
delayedOperations: [],
failure: null,
operationInProgress: false,
skipNonRestrictedTasks: false,
timerIdsToSkip: [],
backoff: [ExponentialBackoff],
visibilityHandler: [Function (anonymous)]
}
},
_persistenceProvider: IndexedDbPersistenceProvider {},
INTERNAL: { delete: [Function: delete] },
_appCompat: FirebaseAppImpl {
_delegate: FirebaseAppImpl {
_isDeleted: false,
_options: [Object],
_config: [Object],
_name: '_Firebase_RulesUnitTesting_1680224130695_0.0042143144476949335',
_automaticDataCollectionEnabled: false,
_container: [ComponentContainer]
},
firebase: <ref *1> {
__esModule: true,
initializeApp: [Function: initializeAppCompat],
app: [Function],
registerVersion: [Function: registerVersion],
setLogLevel: [Function: setLogLevel],
onLog: [Function: onLog],
apps: [Getter],
SDK_VERSION: '9.19.0',
INTERNAL: [Object],
default: [Circular *1],
database: [Function],
firestore: [Function],
storage: [Function]
},
container: ComponentContainer {
name: '_Firebase_RulesUnitTesting_1680224130695_0.0042143144476949335',
providers: [Map]
}
}
}
✔ should allow to read offers for any user (1049ms)

1 passing (1s)

最新更新