diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme
index 3df8b77a24..9b2979aa71 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme
@@ -734,6 +734,104 @@
ReferencedContainer = "container:">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FirebaseFirestoreTestingSupport.podspec b/FirebaseFirestoreTestingSupport.podspec
new file mode 100644
index 0000000000..452a6cf9b5
--- /dev/null
+++ b/FirebaseFirestoreTestingSupport.podspec
@@ -0,0 +1,58 @@
+Pod::Spec.new do |s|
+ s.name = 'FirebaseFirestoreTestingSupport'
+ s.version = '1.0.0'
+ s.summary = 'Firebase SDKs testing support types and utilities.'
+
+ s.description = <<-DESC
+ Type declarations and utilities needed for unit testing of the code dependent on Firebase SDKs
+ DESC
+
+ s.homepage = 'https://developers.google.com/'
+ s.license = { :type => 'Apache', :file => 'LICENSE' }
+ s.authors = 'Google, Inc.'
+
+ s.source = {
+ :git => 'https://github.com/Firebase/firebase-ios-sdk.git',
+ :tag => 'CocoaPods-' + s.version.to_s
+ }
+
+ ios_deployment_target = '10.0'
+ osx_deployment_target = '10.12'
+ tvos_deployment_target = '10.0'
+ watchos_deployment_target = '6.0'
+
+ s.ios.deployment_target = ios_deployment_target
+ s.osx.deployment_target = osx_deployment_target
+ s.tvos.deployment_target = tvos_deployment_target
+ s.watchos.deployment_target = watchos_deployment_target
+
+ s.cocoapods_version = '>= 1.4.0'
+ s.prefix_header_file = false
+ s.requires_arc = true
+
+ base_dir = 'FirebaseTestingSupport/Firestore/'
+
+ s.source_files = [
+ base_dir + 'Sources/**/*.{m,mm,h}',
+ 'Firestore/Source/API/*\+Internal.h'
+ ]
+
+ s.public_header_files = base_dir + '**/*.h'
+
+ s.dependency 'FirebaseFirestore', '~> 7.7'
+
+ s.pod_target_xcconfig = {
+ 'GCC_C_LANGUAGE_STANDARD' => 'c99',
+ 'OTHER_CFLAGS' => '-fno-autolink',
+ 'HEADER_SEARCH_PATHS' =>
+ '"${PODS_TARGET_SRCROOT}" '
+ }
+
+ s.test_spec 'unit' do |unit_tests|
+ unit_tests.scheme = { :code_coverage => true }
+ unit_tests.platforms = {:ios => ios_deployment_target, :osx => osx_deployment_target, :tvos => tvos_deployment_target}
+ unit_tests.source_files = [
+ base_dir + 'Tests/**/*.swift'
+ ]
+ end
+end
diff --git a/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm b/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm
new file mode 100644
index 0000000000..cf100a2742
--- /dev/null
+++ b/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm
@@ -0,0 +1,32 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h"
+
+#import "Firestore/Source/API/FIRQuery+Internal.h"
+
+@implementation FIRQueryFake
+
+- (instancetype)init {
+ // The object is partially initialized. Make sure the methods used during testing are overridden.
+ return self;
+}
+
+- (void)getDocumentsWithCompletion:(FIRQuerySnapshotBlock)completion {
+ if (self.getDocumentsHandler) {
+ self.getDocumentsHandler(completion);
+ }
+}
+
+@end
diff --git a/FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h b/FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h
new file mode 100644
index 0000000000..f7db2c7ee0
--- /dev/null
+++ b/FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h
@@ -0,0 +1,34 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void (^FIRFirestoreGetDocumentsHandler)(FIRQuerySnapshotBlock completion);
+
+/// A fake object to replace a real `Query` in tests.
+NS_SWIFT_NAME(QueryFake)
+@interface FIRQueryFake : FIRQuery
+
+- (instancetype)init;
+
+/// The block to be called each time when `getDocuments(completion:)` method is called.
+@property(nonatomic, nullable, copy) FIRFirestoreGetDocumentsHandler getDocumentsHandler;
+
+// TODO: Implement other handlers as needed.
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift b/FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift
new file mode 100644
index 0000000000..647d85ae13
--- /dev/null
+++ b/FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift
@@ -0,0 +1,44 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import XCTest
+@testable import FirebaseFirestoreTestingSupport
+
+class QueryFakeTests: XCTestCase {
+ func testQueryFakeConstructor() throws {
+ let fakeQuery = QueryFake()
+ XCTAssertNotNil(fakeQuery)
+ XCTAssertTrue(fakeQuery.isKind(of: Query.self))
+ }
+
+ func testQueryFakeGetDocumentsHandler() {
+ let fakeQuery = QueryFake()
+
+ let handlerExpectation = expectation(description: "Handler called")
+ fakeQuery.getDocumentsHandler = { completion in
+ handlerExpectation.fulfill()
+
+ completion(nil, nil)
+ }
+
+ let completionExpectation = expectation(description: "Completion called")
+ fakeQuery.getDocuments { snapshot, error in
+ completionExpectation.fulfill()
+ XCTAssertNil(snapshot)
+ XCTAssertNil(error)
+ }
+
+ wait(for: [handlerExpectation, completionExpectation], timeout: 0.5)
+ }
+}
diff --git a/FirebaseTestingSupport/README.md b/FirebaseTestingSupport/README.md
new file mode 100644
index 0000000000..91cf8fc4e5
--- /dev/null
+++ b/FirebaseTestingSupport/README.md
@@ -0,0 +1,53 @@
+# Firebase Testing Support (for automated test developers)
+
+Firebase Testing Support is a collection of libraries that provide type definitions and tools required for writing tests for code that uses Firebase, e.g.:
+
+- Instances of types like `Query` cannot be created with a simple constructor which makes unit testing of the code that depends on them difficult/impossible. Firestore Testing Support lib provides a type `QueryFake` that can be instantiated and used instead of actual `Query` instances in the tests.
+
+## Usage
+
+### Add dependency to your test target
+
+#### Cocoapods
+
+```
+tests.dependency 'FirebaseFirestoreTestingSupport', '~> 1.0'
+```
+
+#### Swift Package Manager
+
+```
+dependencies: [
+ ...
+ "FirebaseFirestoreTestingSupport"
+],
+
+```
+
+### Use the fake types in the tests instead of real types
+
+See test for example, e.g. [QueryFakeTests.swift](../FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift).
+
+## Development
+
+### Generate project
+
+#### Cocoapods
+
+E.g. for `FirebaseFirestoreTestingSupport` run the following command for the root repo directory:
+
+```
+pod gen --auto-open --local-sources=./ FirebaseFirestoreTestingSupport.podspec --platforms=ios
+```
+
+#### Swift Package Manager
+
+- Open the main package definition:
+
+```
+xed Package.swift
+```
+
+- Select (or add if not exists yet) a scheme for the test target, e.g. `FirestoreTestingSupportTests`
+
+- make required modifications and run tests as needed.
\ No newline at end of file
diff --git a/Package.swift b/Package.swift
index 489a826bc7..c1619eb714 100644
--- a/Package.swift
+++ b/Package.swift
@@ -837,6 +837,28 @@ let package = Package(
.define("FIR_VERSION", to: firebaseVersion),
]
),
+
+ // MARK: Testing support
+
+ .target(
+ name: "FirebaseFirestoreTestingSupport",
+ dependencies: ["FirebaseFirestore"],
+ path: "FirebaseTestingSupport/Firestore/Sources",
+ publicHeadersPath: "./",
+ cSettings: [
+ .headerSearchPath("../../.."),
+ .headerSearchPath("../../../Firestore/Source/Public/FirebaseFirestore"),
+ ]
+ ),
+ .testTarget(
+ name: "FirestoreTestingSupportTests",
+ dependencies: ["FirebaseFirestoreTestingSupport"],
+ path: "FirebaseTestingSupport/Firestore/Tests",
+ cSettings: [
+ .headerSearchPath("../../.."),
+ ]
+ ),
+
],
cLanguageStandard: .c99,
cxxLanguageStandard: CXXLanguageStandard.gnucxx14