diff --git a/js-sdk-framework-tests/nextjs/app/tests/data_connect/web_client/page.tsx b/js-sdk-framework-tests/nextjs/app/tests/data_connect/web_client/page.tsx
new file mode 100644
index 0000000..f40069f
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/app/tests/data_connect/web_client/page.tsx
@@ -0,0 +1,31 @@
+/**
+ * @license
+ * Copyright 2025 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 type { Metadata } from 'next'
+import CSRTestRunner from '@/components/app_tests/data_connect/csr_test_runner';
+
+export const metadata: Metadata = {
+ title: 'Data Connect Web SDK CSR test'
+}
+
+export default function Page() {
+ return (
+ <>
+
Data Connect CSR Test results:
+
+ >
+ );
+}
diff --git a/js-sdk-framework-tests/nextjs/app/tests/data_connect/web_ssr/page.tsx b/js-sdk-framework-tests/nextjs/app/tests/data_connect/web_ssr/page.tsx
new file mode 100644
index 0000000..f6ec11d
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/app/tests/data_connect/web_ssr/page.tsx
@@ -0,0 +1,36 @@
+/**
+ * @license
+ * Copyright 2025 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 type { Metadata } from 'next'
+import { testDataConnect, TestResults } from '@/lib/app_tests/data_connect/test';
+import ResultsDisplay from '@/components/app_tests/data_connect/results_display';
+
+// Suppress static site generation.
+export const dynamic = "force-dynamic";
+
+export const metadata: Metadata = {
+ title: 'Data Connect Web SDK SSR test'
+}
+
+export default async function Page() {
+ const testResults: TestResults = await testDataConnect(/*isServer=*/true);
+ return (
+ <>
+
Data Connect SSR Test results:
+
+ >
+ );
+}
diff --git a/js-sdk-framework-tests/nextjs/src/components/app_tests/data_connect/csr_test_runner.tsx b/js-sdk-framework-tests/nextjs/src/components/app_tests/data_connect/csr_test_runner.tsx
new file mode 100644
index 0000000..d2cfc03
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/components/app_tests/data_connect/csr_test_runner.tsx
@@ -0,0 +1,40 @@
+/**
+ * @license
+ * Copyright 2025 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.
+ */
+'use client'
+
+import { useState, useEffect } from 'react'
+import { testDataConnect, initializeTestResults } from '@/lib/app_tests/data_connect/test';
+import ResultsDisplay from './results_display';
+
+export default function CsrTestRunner() {
+ const [testStatus, setTestStatus] = useState("running...");
+ const [testResults, setTestResults] = useState(initializeTestResults());
+ useEffect(() => {
+ const asyncTest = async () => {
+ setTestResults(await testDataConnect());
+ setTestStatus("Complete!");
+ }
+ asyncTest().catch((e) => {
+ console.error("Error encountered during testing: ", e);
+ setTestStatus("Errored!");
+ });
+ }, []);
+
+ return (
+
+ );
+}
diff --git a/js-sdk-framework-tests/nextjs/src/components/app_tests/data_connect/results_display.tsx b/js-sdk-framework-tests/nextjs/src/components/app_tests/data_connect/results_display.tsx
new file mode 100644
index 0000000..d9c53e7
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/components/app_tests/data_connect/results_display.tsx
@@ -0,0 +1,37 @@
+/**
+ * @license
+ * Copyright 2025 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 Link from 'next/link';
+export default function ResultsDisplay({ statusString, testResults }) {
+ return (
+ <>
+
+
+ Back to test index
+ >
+ );
+}
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/README.md b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/README.md
new file mode 100644
index 0000000..3e7fd61
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/README.md
@@ -0,0 +1,506 @@
+# Generated TypeScript README
+This README will guide you through the process of using the generated JavaScript SDK package for the connector `tests`. It will also provide examples on how to use your generated SDK to call your Data Connect queries and mutations.
+
+***NOTE:** This README is generated alongside the generated SDK. If you make changes to this file, they will be overwritten when the SDK is regenerated.*
+
+# Table of Contents
+- [**Overview**](#generated-javascript-readme)
+- [**Accessing the connector**](#accessing-the-connector)
+ - [*Connecting to the local Emulator*](#connecting-to-the-local-emulator)
+- [**Queries**](#queries)
+ - [*ListPosts*](#listposts)
+ - [*UnauthorizedQuery*](#unauthorizedquery)
+- [**Mutations**](#mutations)
+ - [*RemovePost*](#removepost)
+ - [*AddPost*](#addpost)
+
+# Accessing the connector
+A connector is a collection of Queries and Mutations. One SDK is generated for each connector - this SDK is generated for the connector `tests`. You can find more information about connectors in the [Data Connect documentation](https://firebase.google.com/docs/data-connect#how-does).
+
+You can use this generated SDK by importing from the package `@firebasegen/tests-connector` as shown below. Both CommonJS and ESM imports are supported.
+
+You can also follow the instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#set-client).
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig } from '@firebasegen/tests-connector';
+
+const dataConnect = getDataConnect(connectorConfig);
+```
+
+## Connecting to the local Emulator
+By default, the connector will connect to the production service.
+
+To connect to the emulator, you can use the following code.
+You can also follow the emulator instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#instrument-clients).
+
+```typescript
+import { connectDataConnectEmulator, getDataConnect } from 'firebase/data-connect';
+import { connectorConfig } from '@firebasegen/tests-connector';
+
+const dataConnect = getDataConnect(connectorConfig);
+connectDataConnectEmulator(dataConnect, 'localhost', 9399);
+```
+
+After it's initialized, you can call your Data Connect [queries](#queries) and [mutations](#mutations) from your generated SDK.
+
+# Queries
+
+There are two ways to execute a Data Connect Query using the generated Web SDK:
+- Using a Query Reference function, which returns a `QueryRef`
+ - The `QueryRef` can be used as an argument to `executeQuery()`, which will execute the Query and return a `QueryPromise`
+- Using an action shortcut function, which returns a `QueryPromise`
+ - Calling the action shortcut function will execute the Query and return a `QueryPromise`
+
+The following is true for both the action shortcut function and the `QueryRef` function:
+- The `QueryPromise` returned will resolve to the result of the Query once it has finished executing
+- If the Query accepts arguments, both the action shortcut function and the `QueryRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Query
+- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you.
+
+Below are examples of how to use the `tests` connector's generated functions to execute each query. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-queries).
+
+## ListPosts
+You can execute the `ListPosts` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [tests-connector/index.d.ts](./index.d.ts):
+```typescript
+listPosts(vars: ListPostsVariables): QueryPromise;
+
+interface ListPostsRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: ListPostsVariables): QueryRef;
+}
+export const listPostsRef: ListPostsRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listPosts(dc: DataConnect, vars: ListPostsVariables): QueryPromise;
+
+interface ListPostsRef {
+ ...
+ (dc: DataConnect, vars: ListPostsVariables): QueryRef;
+}
+export const listPostsRef: ListPostsRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listPostsRef:
+```typescript
+const name = listPostsRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `ListPosts` query requires an argument of type `ListPostsVariables`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface ListPostsVariables {
+ testId: string;
+}
+```
+### Return Type
+Recall that executing the `ListPosts` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListPostsData`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListPostsData {
+ posts: ({
+ id: UUIDString;
+ description: string;
+ } & Post_Key)[];
+}
+```
+### Using `ListPosts`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listPosts, ListPostsVariables } from '@firebasegen/tests-connector';
+
+// The `ListPosts` query requires an argument of type `ListPostsVariables`:
+const listPostsVars: ListPostsVariables = {
+ testId: ...,
+};
+
+// Call the `listPosts()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listPosts(listPostsVars);
+// Variables can be defined inline as well.
+const { data } = await listPosts({ testId: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listPosts(dataConnect, listPostsVars);
+
+console.log(data.posts);
+
+// Or, you can use the `Promise` API.
+listPosts(listPostsVars).then((response) => {
+ const data = response.data;
+ console.log(data.posts);
+});
+```
+
+### Using `ListPosts`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listPostsRef, ListPostsVariables } from '@firebasegen/tests-connector';
+
+// The `ListPosts` query requires an argument of type `ListPostsVariables`:
+const listPostsVars: ListPostsVariables = {
+ testId: ...,
+};
+
+// Call the `listPostsRef()` function to get a reference to the query.
+const ref = listPostsRef(listPostsVars);
+// Variables can be defined inline as well.
+const ref = listPostsRef({ testId: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listPostsRef(dataConnect, listPostsVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.posts);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.posts);
+});
+```
+
+## UnauthorizedQuery
+You can execute the `UnauthorizedQuery` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [tests-connector/index.d.ts](./index.d.ts):
+```typescript
+unauthorizedQuery(): QueryPromise;
+
+interface UnauthorizedQueryRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const unauthorizedQueryRef: UnauthorizedQueryRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+unauthorizedQuery(dc: DataConnect): QueryPromise;
+
+interface UnauthorizedQueryRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const unauthorizedQueryRef: UnauthorizedQueryRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the unauthorizedQueryRef:
+```typescript
+const name = unauthorizedQueryRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `UnauthorizedQuery` query has no variables.
+### Return Type
+Recall that executing the `UnauthorizedQuery` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `UnauthorizedQueryData`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface UnauthorizedQueryData {
+ posts: ({
+ id: UUIDString;
+ description: string;
+ } & Post_Key)[];
+}
+```
+### Using `UnauthorizedQuery`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, unauthorizedQuery } from '@firebasegen/tests-connector';
+
+
+// Call the `unauthorizedQuery()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await unauthorizedQuery();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await unauthorizedQuery(dataConnect);
+
+console.log(data.posts);
+
+// Or, you can use the `Promise` API.
+unauthorizedQuery().then((response) => {
+ const data = response.data;
+ console.log(data.posts);
+});
+```
+
+### Using `UnauthorizedQuery`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, unauthorizedQueryRef } from '@firebasegen/tests-connector';
+
+
+// Call the `unauthorizedQueryRef()` function to get a reference to the query.
+const ref = unauthorizedQueryRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = unauthorizedQueryRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.posts);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.posts);
+});
+```
+
+# Mutations
+
+There are two ways to execute a Data Connect Mutation using the generated Web SDK:
+- Using a Mutation Reference function, which returns a `MutationRef`
+ - The `MutationRef` can be used as an argument to `executeMutation()`, which will execute the Mutation and return a `MutationPromise`
+- Using an action shortcut function, which returns a `MutationPromise`
+ - Calling the action shortcut function will execute the Mutation and return a `MutationPromise`
+
+The following is true for both the action shortcut function and the `MutationRef` function:
+- The `MutationPromise` returned will resolve to the result of the Mutation once it has finished executing
+- If the Mutation accepts arguments, both the action shortcut function and the `MutationRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Mutation
+- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you.
+
+Below are examples of how to use the `tests` connector's generated functions to execute each mutation. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-mutations).
+
+## RemovePost
+You can execute the `RemovePost` mutation using the following action shortcut function, or by calling `executeMutation()` after calling the following `MutationRef` function, both of which are defined in [tests-connector/index.d.ts](./index.d.ts):
+```typescript
+removePost(vars: RemovePostVariables): MutationPromise;
+
+interface RemovePostRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: RemovePostVariables): MutationRef;
+}
+export const removePostRef: RemovePostRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `MutationRef` function.
+```typescript
+removePost(dc: DataConnect, vars: RemovePostVariables): MutationPromise;
+
+interface RemovePostRef {
+ ...
+ (dc: DataConnect, vars: RemovePostVariables): MutationRef;
+}
+export const removePostRef: RemovePostRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the removePostRef:
+```typescript
+const name = removePostRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `RemovePost` mutation requires an argument of type `RemovePostVariables`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface RemovePostVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `RemovePost` mutation returns a `MutationPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `RemovePostData`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface RemovePostData {
+ post_delete?: Post_Key | null;
+}
+```
+### Using `RemovePost`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, removePost, RemovePostVariables } from '@firebasegen/tests-connector';
+
+// The `RemovePost` mutation requires an argument of type `RemovePostVariables`:
+const removePostVars: RemovePostVariables = {
+ id: ...,
+};
+
+// Call the `removePost()` function to execute the mutation.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await removePost(removePostVars);
+// Variables can be defined inline as well.
+const { data } = await removePost({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await removePost(dataConnect, removePostVars);
+
+console.log(data.post_delete);
+
+// Or, you can use the `Promise` API.
+removePost(removePostVars).then((response) => {
+ const data = response.data;
+ console.log(data.post_delete);
+});
+```
+
+### Using `RemovePost`'s `MutationRef` function
+
+```typescript
+import { getDataConnect, executeMutation } from 'firebase/data-connect';
+import { connectorConfig, removePostRef, RemovePostVariables } from '@firebasegen/tests-connector';
+
+// The `RemovePost` mutation requires an argument of type `RemovePostVariables`:
+const removePostVars: RemovePostVariables = {
+ id: ...,
+};
+
+// Call the `removePostRef()` function to get a reference to the mutation.
+const ref = removePostRef(removePostVars);
+// Variables can be defined inline as well.
+const ref = removePostRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `MutationRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = removePostRef(dataConnect, removePostVars);
+
+// Call `executeMutation()` on the reference to execute the mutation.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeMutation(ref);
+
+console.log(data.post_delete);
+
+// Or, you can use the `Promise` API.
+executeMutation(ref).then((response) => {
+ const data = response.data;
+ console.log(data.post_delete);
+});
+```
+
+## AddPost
+You can execute the `AddPost` mutation using the following action shortcut function, or by calling `executeMutation()` after calling the following `MutationRef` function, both of which are defined in [tests-connector/index.d.ts](./index.d.ts):
+```typescript
+addPost(vars: AddPostVariables): MutationPromise;
+
+interface AddPostRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: AddPostVariables): MutationRef;
+}
+export const addPostRef: AddPostRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `MutationRef` function.
+```typescript
+addPost(dc: DataConnect, vars: AddPostVariables): MutationPromise;
+
+interface AddPostRef {
+ ...
+ (dc: DataConnect, vars: AddPostVariables): MutationRef;
+}
+export const addPostRef: AddPostRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the addPostRef:
+```typescript
+const name = addPostRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `AddPost` mutation requires an argument of type `AddPostVariables`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface AddPostVariables {
+ id: UUIDString;
+ description: string;
+ testId: string;
+}
+```
+### Return Type
+Recall that executing the `AddPost` mutation returns a `MutationPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `AddPostData`, which is defined in [tests-connector/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface AddPostData {
+ post_insert: Post_Key;
+}
+```
+### Using `AddPost`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, addPost, AddPostVariables } from '@firebasegen/tests-connector';
+
+// The `AddPost` mutation requires an argument of type `AddPostVariables`:
+const addPostVars: AddPostVariables = {
+ id: ...,
+ description: ...,
+ testId: ...,
+};
+
+// Call the `addPost()` function to execute the mutation.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await addPost(addPostVars);
+// Variables can be defined inline as well.
+const { data } = await addPost({ id: ..., description: ..., testId: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await addPost(dataConnect, addPostVars);
+
+console.log(data.post_insert);
+
+// Or, you can use the `Promise` API.
+addPost(addPostVars).then((response) => {
+ const data = response.data;
+ console.log(data.post_insert);
+});
+```
+
+### Using `AddPost`'s `MutationRef` function
+
+```typescript
+import { getDataConnect, executeMutation } from 'firebase/data-connect';
+import { connectorConfig, addPostRef, AddPostVariables } from '@firebasegen/tests-connector';
+
+// The `AddPost` mutation requires an argument of type `AddPostVariables`:
+const addPostVars: AddPostVariables = {
+ id: ...,
+ description: ...,
+ testId: ...,
+};
+
+// Call the `addPostRef()` function to get a reference to the mutation.
+const ref = addPostRef(addPostVars);
+// Variables can be defined inline as well.
+const ref = addPostRef({ id: ..., description: ..., testId: ..., });
+
+// You can also pass in a `DataConnect` instance to the `MutationRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = addPostRef(dataConnect, addPostVars);
+
+// Call `executeMutation()` on the reference to execute the mutation.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeMutation(ref);
+
+console.log(data.post_insert);
+
+// Or, you can use the `Promise` API.
+executeMutation(ref).then((response) => {
+ const data = response.data;
+ console.log(data.post_insert);
+});
+```
+
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/esm/index.esm.js b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/esm/index.esm.js
new file mode 100644
index 0000000..4603166
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/esm/index.esm.js
@@ -0,0 +1,52 @@
+import { queryRef, executeQuery, mutationRef, executeMutation, validateArgs } from 'firebase/data-connect';
+
+export const connectorConfig = {
+ connector: 'tests',
+ service: 'fdc-service',
+ location: 'us-west2'
+};
+
+export const removePostRef = (dcOrVars, vars) => {
+ const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+ dcInstance._useGeneratedSdk();
+ return mutationRef(dcInstance, 'RemovePost', inputVars);
+}
+removePostRef.operationName = 'RemovePost';
+
+export function removePost(dcOrVars, vars) {
+ return executeMutation(removePostRef(dcOrVars, vars));
+}
+
+export const addPostRef = (dcOrVars, vars) => {
+ const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+ dcInstance._useGeneratedSdk();
+ return mutationRef(dcInstance, 'AddPost', inputVars);
+}
+addPostRef.operationName = 'AddPost';
+
+export function addPost(dcOrVars, vars) {
+ return executeMutation(addPostRef(dcOrVars, vars));
+}
+
+export const listPostsRef = (dcOrVars, vars) => {
+ const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+ dcInstance._useGeneratedSdk();
+ return queryRef(dcInstance, 'ListPosts', inputVars);
+}
+listPostsRef.operationName = 'ListPosts';
+
+export function listPosts(dcOrVars, vars) {
+ return executeQuery(listPostsRef(dcOrVars, vars));
+}
+
+export const unauthorizedQueryRef = (dc) => {
+ const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined);
+ dcInstance._useGeneratedSdk();
+ return queryRef(dcInstance, 'UnauthorizedQuery');
+}
+unauthorizedQueryRef.operationName = 'UnauthorizedQuery';
+
+export function unauthorizedQuery(dc) {
+ return executeQuery(unauthorizedQueryRef(dc));
+}
+
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/esm/package.json b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/esm/package.json
new file mode 100644
index 0000000..7c34deb
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/esm/package.json
@@ -0,0 +1 @@
+{"type":"module"}
\ No newline at end of file
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/index.cjs.js b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/index.cjs.js
new file mode 100644
index 0000000..0fb12ec
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/index.cjs.js
@@ -0,0 +1,56 @@
+const { queryRef, executeQuery, mutationRef, executeMutation, validateArgs } = require('firebase/data-connect');
+
+const connectorConfig = {
+ connector: 'tests',
+ service: 'fdc-service',
+ location: 'us-west2'
+};
+exports.connectorConfig = connectorConfig;
+
+const removePostRef = (dcOrVars, vars) => {
+ const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+ dcInstance._useGeneratedSdk();
+ return mutationRef(dcInstance, 'RemovePost', inputVars);
+}
+removePostRef.operationName = 'RemovePost';
+exports.removePostRef = removePostRef;
+
+exports.removePost = function removePost(dcOrVars, vars) {
+ return executeMutation(removePostRef(dcOrVars, vars));
+};
+
+const addPostRef = (dcOrVars, vars) => {
+ const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+ dcInstance._useGeneratedSdk();
+ return mutationRef(dcInstance, 'AddPost', inputVars);
+}
+addPostRef.operationName = 'AddPost';
+exports.addPostRef = addPostRef;
+
+exports.addPost = function addPost(dcOrVars, vars) {
+ return executeMutation(addPostRef(dcOrVars, vars));
+};
+
+const listPostsRef = (dcOrVars, vars) => {
+ const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+ dcInstance._useGeneratedSdk();
+ return queryRef(dcInstance, 'ListPosts', inputVars);
+}
+listPostsRef.operationName = 'ListPosts';
+exports.listPostsRef = listPostsRef;
+
+exports.listPosts = function listPosts(dcOrVars, vars) {
+ return executeQuery(listPostsRef(dcOrVars, vars));
+};
+
+const unauthorizedQueryRef = (dc) => {
+ const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined);
+ dcInstance._useGeneratedSdk();
+ return queryRef(dcInstance, 'UnauthorizedQuery');
+}
+unauthorizedQueryRef.operationName = 'UnauthorizedQuery';
+exports.unauthorizedQueryRef = unauthorizedQueryRef;
+
+exports.unauthorizedQuery = function unauthorizedQuery(dc) {
+ return executeQuery(unauthorizedQueryRef(dc));
+};
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/index.d.ts b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/index.d.ts
new file mode 100644
index 0000000..b27202f
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/index.d.ts
@@ -0,0 +1,101 @@
+import { ConnectorConfig, DataConnect, QueryRef, QueryPromise, MutationRef, MutationPromise } from 'firebase/data-connect';
+
+export const connectorConfig: ConnectorConfig;
+
+export type TimestampString = string;
+export type UUIDString = string;
+export type Int64String = string;
+export type DateString = string;
+
+
+
+
+export interface AddPostData {
+ post_insert: Post_Key;
+}
+
+export interface AddPostVariables {
+ id: UUIDString;
+ description: string;
+ testId: string;
+}
+
+export interface ListPostsData {
+ posts: ({
+ id: UUIDString;
+ description: string;
+ } & Post_Key)[];
+}
+
+export interface ListPostsVariables {
+ testId: string;
+}
+
+export interface Post_Key {
+ id: UUIDString;
+ __typename?: 'Post_Key';
+}
+
+export interface RemovePostData {
+ post_delete?: Post_Key | null;
+}
+
+export interface RemovePostVariables {
+ id: UUIDString;
+}
+
+export interface UnauthorizedQueryData {
+ posts: ({
+ id: UUIDString;
+ description: string;
+ } & Post_Key)[];
+}
+
+interface RemovePostRef {
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: RemovePostVariables): MutationRef;
+ /* Allow users to pass in custom DataConnect instances */
+ (dc: DataConnect, vars: RemovePostVariables): MutationRef;
+ operationName: string;
+}
+export const removePostRef: RemovePostRef;
+
+export function removePost(vars: RemovePostVariables): MutationPromise;
+export function removePost(dc: DataConnect, vars: RemovePostVariables): MutationPromise;
+
+interface AddPostRef {
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: AddPostVariables): MutationRef;
+ /* Allow users to pass in custom DataConnect instances */
+ (dc: DataConnect, vars: AddPostVariables): MutationRef;
+ operationName: string;
+}
+export const addPostRef: AddPostRef;
+
+export function addPost(vars: AddPostVariables): MutationPromise;
+export function addPost(dc: DataConnect, vars: AddPostVariables): MutationPromise;
+
+interface ListPostsRef {
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: ListPostsVariables): QueryRef;
+ /* Allow users to pass in custom DataConnect instances */
+ (dc: DataConnect, vars: ListPostsVariables): QueryRef;
+ operationName: string;
+}
+export const listPostsRef: ListPostsRef;
+
+export function listPosts(vars: ListPostsVariables): QueryPromise;
+export function listPosts(dc: DataConnect, vars: ListPostsVariables): QueryPromise;
+
+interface UnauthorizedQueryRef {
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+ /* Allow users to pass in custom DataConnect instances */
+ (dc: DataConnect): QueryRef;
+ operationName: string;
+}
+export const unauthorizedQueryRef: UnauthorizedQueryRef;
+
+export function unauthorizedQuery(): QueryPromise;
+export function unauthorizedQuery(dc: DataConnect): QueryPromise;
+
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/package.json b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/package.json
new file mode 100644
index 0000000..e8e66ea
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/dataconnect-generated/js/tests-connector/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "@firebasegen/tests-connector",
+ "version": "1.0.0",
+ "author": "Firebase (https://firebase.google.com/)",
+ "description": "Generated SDK For tests",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": " >=18.0"
+ },
+ "typings": "index.d.ts",
+ "module": "esm/index.esm.js",
+ "main": "index.cjs.js",
+ "browser": "esm/index.esm.js",
+ "exports": {
+ ".": {
+ "types": "./index.d.ts",
+ "require": "./index.cjs.js",
+ "default": "./esm/index.esm.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "peerDependencies": {
+ "firebase": "^10.14.0 || ^11.3.0"
+ }
+}
\ No newline at end of file
diff --git a/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/test.ts b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/test.ts
new file mode 100644
index 0000000..7e15740
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/src/lib/app_tests/data_connect/test.ts
@@ -0,0 +1,135 @@
+/**
+ * @license
+ * Copyright 2025 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 { deleteApp, initializeApp } from 'firebase/app';
+import { getAuth, signInAnonymously } from 'firebase/auth';
+import { firebaseConfig } from '@/lib/app_tests/firebase';
+import { OK, OK_SKIPPED, FAILED } from '@/lib/app_tests/util';
+
+import {
+ AddPostVariables,
+ ListPostsVariables,
+ RemovePostVariables,
+ addPost,
+ listPosts,
+ removePost
+} from './dataconnect-generated/js/tests-connector';
+
+export type TestResults = {
+ initializeAppResult: string,
+ initializeAuthResult: string,
+ signInAnonymouslyresult: string,
+ addPostResult: string,
+ listPostsResult: string,
+ foundPostResult: string,
+ removePostResult: string,
+ requeryPostsResult: string,
+ confirmedPostDeletedResult: string,
+ deleteUserResult: string,
+ deleteAppResult: string,
+};
+
+export function initializeTestResults(): TestResults {
+ return {
+ initializeAppResult: FAILED,
+ initializeAuthResult: FAILED,
+ signInAnonymouslyresult: FAILED,
+ addPostResult: FAILED,
+ listPostsResult: FAILED,
+ foundPostResult: FAILED,
+ removePostResult: FAILED,
+ requeryPostsResult: FAILED,
+ confirmedPostDeletedResult: FAILED,
+ deleteUserResult: FAILED,
+ deleteAppResult: FAILED
+ };
+}
+export async function testDataConnect(isServer: boolean = false): Promise {
+ const result: TestResults = initializeTestResults();
+ try {
+ const firebaseApp = initializeApp(firebaseConfig);
+ if (firebaseApp === null) {
+ return result;
+ }
+ result.initializeAppResult = OK;
+
+ const auth = getAuth(firebaseApp);
+ result.initializeAuthResult = OK;
+
+ await signInAnonymously(auth);
+ result.signInAnonymouslyresult = OK;
+
+ const POST_ID = crypto.randomUUID();
+ const DESCRIPTION : string = "next js night test post.";
+ const TEST_ID : string = "nextjs-nightly-test";
+
+ const addPostVars : AddPostVariables = {
+ id: POST_ID,
+ description: DESCRIPTION,
+ testId: TEST_ID
+ }
+ await addPost(addPostVars);
+ result.addPostResult = OK;
+
+ const listPostVars : ListPostsVariables = {
+ testId: TEST_ID
+ }
+ const posts = await listPosts(listPostVars);
+ result.listPostsResult = OK;
+
+ // Data connect removes the `-` from the UUID.
+ const comparablePostId = POST_ID.replaceAll('-', '');
+ if(posts.data.posts.find((post) =>
+ post.id === comparablePostId && post.description == DESCRIPTION
+ )) {
+ result.foundPostResult = OK;
+ }
+
+ const removePostVars : RemovePostVariables = {
+ id: POST_ID
+ }
+ await removePost(removePostVars);
+ result.removePostResult = OK;
+
+ const relistPosts = await listPosts(listPostVars);
+ result.requeryPostsResult = OK;
+
+ if(relistPosts.data.posts.find((post) =>
+ post.id === comparablePostId && post.description == DESCRIPTION
+ )) {
+ result.confirmedPostDeletedResult = OK;
+ }
+
+ if(auth.currentUser) {
+ await auth.currentUser!.delete();
+ result.deleteUserResult = OK;
+ }
+
+ // Note: Deleting the app hangs the SSR pass on playwright on Firefox
+ // and Chromium, but the hang does not occur when manually testing with
+ // those browsers.
+ if (isServer) {
+ result.deleteAppResult = OK_SKIPPED;
+ } else {
+ deleteApp(firebaseApp);
+ result.deleteAppResult = OK;
+ }
+ } catch (e) {
+ console.log("Caught error: ", e);
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/js-sdk-framework-tests/nextjs/tests/data_connect.spec.ts b/js-sdk-framework-tests/nextjs/tests/data_connect.spec.ts
new file mode 100644
index 0000000..c57802f
--- /dev/null
+++ b/js-sdk-framework-tests/nextjs/tests/data_connect.spec.ts
@@ -0,0 +1,47 @@
+/**
+ * @license
+ * Copyright 2025 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 { test, expect } from '@playwright/test';
+
+test.describe.configure({ mode: 'serial' });
+
+async function commonExpectations(page) {
+ await expect(page.getByTitle('initializeAppResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('initializeAuthResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('signInAnonymouslyresult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('addPostResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('listPostsResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('foundPostResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('removePostResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('requeryPostsResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('confirmedPostDeletedResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('deleteUserResult')).not.toContainText("FAILED");
+ await expect(page.getByTitle('deleteAppResult')).not.toContainText("FAILED");
+}
+
+test('data connect operations should pass - client', async ({ page, baseURL }) => {
+ await page.goto(`${baseURL}/tests/data_connect/web_client`);
+ await expect(page.getByTitle('testStatus')).toContainText('Complete', { timeout: 10000 });
+ await expect(page.locator('h1')).toContainText('Data Connect CSR Test');
+ await commonExpectations(page);
+});
+
+test('data connect operations should pass - server', async ({ page, baseURL }) => {
+ await page.goto(`${baseURL}/tests/data_connect/web_ssr`);
+ await expect(page.getByTitle('testStatus')).toContainText('Complete', { timeout: 10000 });
+ await expect(page.locator('h1')).toContainText('Data Connect SSR Test');
+ await commonExpectations(page);
+});
diff --git a/package.json b/package.json
index 6562c31..c6c99b4 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"build:nextjs": "lerna run build --scope js-sdk-framework-tests-nextjs",
"test:nextjs": "lerna run test --scope js-sdk-framework-tests-nextjs",
"lint:nextjs": "lerna run lint --scope js-sdk-framework-tests-nextjs",
+ "dev:nextjs": "lerna run dev --scope js-sdk-framework-tests-nextjs",
"setup:angular": "lerna run setup --scope js-sdk-framework-tests-angular",
"build:angular": "lerna run build --scope js-sdk-framework-tests-angular",