-
Notifications
You must be signed in to change notification settings - Fork 2.3k
feat(firebase-ai): create ai
package, vertexai
wraps around it
#8555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
russellwheatley
wants to merge
84
commits into
main
Choose a base branch
from
firebase-ai
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
84 commits
Select commit
Hold shift + click to select a range
c17a2c9
chore: initial cp over to ai directory
russellwheatley 06a24a7
refactor: move to AI implementation, including AIModel base class
russellwheatley 44183d6
chore: update types for FirebaseApp to match JS SDK
russellwheatley fd0df2b
chore: update CHANGELOG & package.json
russellwheatley 649eaf5
format
russellwheatley 547ce8a
request-helpers
russellwheatley ea4c130
request.ts
russellwheatley bc0ab3b
response-helpers.ts
russellwheatley 86ddd94
schema-builder.ts
russellwheatley 68f6669
stream-reader.ts
russellwheatley dc3cacb
chat-session-helpers.ts
russellwheatley 0582d8f
chat-session.ts
russellwheatley d65fe3d
count-tokens.ts
russellwheatley 70bf812
generate-content.ts
russellwheatley fc7c77e
models index
russellwheatley 64ae763
enums.ts
russellwheatley 3047eb1
error.ts
russellwheatley 2febfdc
chore: add googleai to exports
russellwheatley 68421ef
request.ts types
russellwheatley e8af3fc
types/responses.ts
russellwheatley 1c24dd9
types/schema.ts
russellwheatley e28877e
test: backend
russellwheatley ba719a5
add license header to test file
russellwheatley cfc0bc8
test: googleai-mapper
russellwheatley d275f19
chore: firebase_ai yarn.lock
russellwheatley 38c1799
test(ai): update unit test for firebase ai
russellwheatley b56cd78
test: update convert mocks in line with latest mock response repo
russellwheatley 25dbed0
test(ai): update script name to run
russellwheatley cb61e8c
test(ai): getMockResponse()
russellwheatley b5c61dc
test(ai): mock-response update for new mocks
russellwheatley 214c235
test(ai): count tokens unit tests
russellwheatley cf2bbd7
test: generate-content mock response
russellwheatley 10d081d
test(ai): update unit tests to use updated mocks
russellwheatley 6541dee
test: fix unit tests
russellwheatley 4102574
test: fixed another unit test suite
russellwheatley 6fb7bda
test: add TS no-check to generated mocks
russellwheatley f210ac4
refactor(vertexai): initial setup to use ai package
russellwheatley 01f9da0
refactor: remove vertexai code and wrap around firebase ai package
russellwheatley 680e9a7
chore: update script name
russellwheatley f26b73b
chore: firebaseerror from utils
russellwheatley 4bd631b
chore: import vertex constant
russellwheatley daa488f
chore(vertexai): rm testing from vertex package
russellwheatley 96de44a
chore: update logger to ai
russellwheatley 1ef56fb
chore(vertexai): rm obsolete files
russellwheatley a285a7c
chore(vertexai): revert back to prev. tsconfig
russellwheatley 70fb2fe
chore(vertexai): symlink ai lib/ folder
russellwheatley e520bf1
chore(vertexai): wrap around ai
russellwheatley f4161fc
chore(vertexai): remove logger
russellwheatley 5a8382f
test(vertexai): rm e2e tests
russellwheatley c307142
refactor: make ai dependency on vertexai
russellwheatley 53ba822
test: fix test
russellwheatley ac4a1ab
fix: do not use RN URL to construct url
russellwheatley 202bbcb
chore(ai): write example app for ai package
russellwheatley 390832b
fix(ai): allow auth and app check to be passed in
russellwheatley 4e69b4e
chore: clean up of exports
russellwheatley 9c43695
chore: rm mock script from vertex
russellwheatley 159fbc3
chore: update linter ignore list
russellwheatley 4315a5f
docs(ai): write usage docs
russellwheatley 87e3968
format
russellwheatley cc698e7
rm note
russellwheatley 2f346ff
scrub TODO
russellwheatley c76a840
test: ensure all types are exported
russellwheatley 99d6439
chore: pr feedback
russellwheatley 203cfd6
chore: rm code comment
russellwheatley 4fefc5a
Apply suggestions from code review
russellwheatley 778fa21
chore: finish string
russellwheatley 83bc393
fix(storage, other): work around missing TextEncoder implementation
mikehardy d25ce24
test(ai): add example app to list of example apps
mikehardy d9b29ed
Update packages/app/lib/modular/index.js
russellwheatley 860a8d6
docs(ai): update CHANGELOG with code change
russellwheatley 9ef763f
chore(ai): license header date
russellwheatley 94281e8
chore(ai): license headers
russellwheatley c22c804
chore(ai): deprecate `totalBillableCharacters`
russellwheatley e59686e
test(ai): update to VertexAI backend
russellwheatley 39bed82
test: create tests for googlebackend as well
russellwheatley 424cd8e
test: fix test
russellwheatley f024c97
chore(ai): license headers
russellwheatley 6f7515b
test(ai): used correct type
russellwheatley eb820bb
docs(ai): mapPromptFeedback() inline documentation
russellwheatley 4be82b3
docs(ai): inline documentation for `countToken()`
russellwheatley 8a38479
docs(ai): generate-content.ts inline docs
russellwheatley 389166e
docs(ai): inline docs for enums.ts
russellwheatley 1089a61
docs(ai): license header date
russellwheatley 961cf50
test(ai): move mock test data fetch to new ai package name
mikehardy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Change Log | ||
|
||
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. | ||
|
||
## Feature | ||
|
||
Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This SDK *replaces* the previous Vertex AI in Firebase SDK (`FirebaseVertexAI`) to accommodate the evolving set of supported features and services. | ||
The new Firebase AI Logic SDK provides **preview** support for the Gemini Developer API, including its free tier offering. | ||
Using the Firebase AI Logic SDK with the Vertex AI Gemini API is still generally available (GA). | ||
|
||
To start using the new SDK, import the `@react-native-firebase/ai` package and use the modular method `getAI()` to initialize. See details in the [migration guide](https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk). | ||
|
||
Please update the following to move from VertexAI to FirebaseAI: | ||
|
||
```js | ||
// BEFORE - using firebase/vertexai | ||
import { initializeApp } from "firebase/app"; | ||
~~import { getVertexAI, getGenerativeModel } from "firebase/vertexai";~~ | ||
|
||
|
||
// AFTER - using firebase/ai | ||
import { initializeApp } from "firebase/app"; | ||
import { getAI, getGenerativeModel } from "firebase/ai"; | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
Apache-2.0 License | ||
------------------ | ||
|
||
Copyright (c) 2016-present Invertase Limited <oss@invertase.io> & Contributors | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this library except in compliance with the License. | ||
|
||
You may obtain a copy of the Apache-2.0 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. | ||
|
||
|
||
Creative Commons Attribution 3.0 License | ||
---------------------------------------- | ||
|
||
Copyright (c) 2016-present Invertase Limited <oss@invertase.io> & Contributors | ||
|
||
Documentation and other instructional materials provided for this project | ||
(including on a separate documentation repository or it's documentation website) are | ||
licensed under the Creative Commons Attribution 3.0 License. Code samples/blocks | ||
contained therein are licensed under the Apache License, Version 2.0 (the "License"), as above. | ||
|
||
You may obtain a copy of the Creative Commons Attribution 3.0 License at | ||
|
||
https://creativecommons.org/licenses/by/3.0/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<p align="center"> | ||
<a href="https://rnfirebase.io"> | ||
<img width="160px" src="https://i.imgur.com/JIyBtKW.png"><br/> | ||
</a> | ||
<h2 align="center">React Native Firebase - AI Logic</h2> | ||
</p> | ||
|
||
<p align="center"> | ||
<a href="https://api.rnfirebase.io/coverage/ai/detail"><img src="https://api.rnfirebase.io/coverage/ai/badge?style=flat-square" alt="Coverage"></a> | ||
<a href="https://www.npmjs.com/package/@react-native-firebase/ai"><img src="https://img.shields.io/npm/dm/@react-native-firebase/ai.svg?style=flat-square" alt="NPM downloads"></a> | ||
<a href="https://www.npmjs.com/package/@react-native-firebase/ai"><img src="https://img.shields.io/npm/v/@react-native-firebase/ai.svg?style=flat-square" alt="NPM version"></a> | ||
<a href="/LICENSE"><img src="https://img.shields.io/npm/l/react-native-firebase.svg?style=flat-square" alt="License"></a> | ||
<a href="https://lerna.js.org/"><img src="https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg?style=flat-square" alt="Maintained with Lerna"></a> | ||
</p> | ||
|
||
<p align="center"> | ||
<a href="https://invertase.link/discord"><img src="https://img.shields.io/discord/295953187817521152.svg?style=flat-square&colorA=7289da&label=Chat%20on%20Discord" alt="Chat on Discord"></a> | ||
<a href="https://twitter.com/rnfirebase"><img src="https://img.shields.io/twitter/follow/rnfirebase.svg?style=flat-square&colorA=1da1f2&colorB=&label=Follow%20on%20Twitter" alt="Follow on Twitter"></a> | ||
<a href="https://www.facebook.com/groups/rnfirebase"><img src="https://img.shields.io/badge/Follow%20on%20Facebook-4172B8?logo=facebook&style=flat-square&logoColor=fff" alt="Follow on Facebook"></a> | ||
</p> | ||
|
||
--- | ||
|
||
Firebase AI Logic gives you access to the latest generative AI models from Google. | ||
|
||
If you need to call the Gemini API directly from your mobile or web app — rather than server-side — you can use the Firebase AI Logic client SDKs. These client SDKs are built specifically for use with mobile and web apps, offering security options against unauthorized clients as well as integrations with other Firebase services. | ||
|
||
[> Learn More](https://firebase.google.com/docs/ai-logic/) | ||
|
||
## Installation | ||
|
||
Requires `@react-native-firebase/app` to be installed. | ||
|
||
```bash | ||
yarn add @react-native-firebase/ai | ||
``` | ||
|
||
## Documentation | ||
|
||
- [Quick Start](https://rnfirebase.io/ai/usage) | ||
|
||
## License | ||
|
||
- See [LICENSE](/LICENSE) | ||
|
||
--- | ||
|
||
<p> | ||
<img align="left" width="75px" src="https://static.invertase.io/assets/invertase-logo-small.png"> | ||
<p align="left"> | ||
Built and maintained with 💛 by <a href="https://invertase.io">Invertase</a>. | ||
</p> | ||
</p> | ||
|
||
--- |
russellwheatley marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/** | ||
* @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 { describe, expect, it } from '@jest/globals'; | ||
import { type ReactNativeFirebase } from '../../app/lib'; | ||
|
||
import { ModelParams, AIErrorCode } from '../lib/types'; | ||
import { AIError } from '../lib/errors'; | ||
import { getGenerativeModel } from '../lib/index'; | ||
|
||
import { AI } from '../lib/public-types'; | ||
import { GenerativeModel } from '../lib/models/generative-model'; | ||
|
||
import { AI_TYPE } from '../lib/constants'; | ||
import { GoogleAIBackend, VertexAIBackend } from '../lib/backend'; | ||
|
||
const fakeAI: AI = { | ||
app: { | ||
name: 'DEFAULT', | ||
options: { | ||
apiKey: 'key', | ||
appId: 'appId', | ||
projectId: 'my-project', | ||
}, | ||
} as ReactNativeFirebase.FirebaseApp, | ||
backend: new VertexAIBackend('us-central1'), | ||
location: 'us-central1', | ||
}; | ||
|
||
const fakeGoogleAI: AI = { | ||
app: { | ||
name: 'DEFAULT', | ||
automaticDataCollectionEnabled: true, | ||
options: { | ||
apiKey: 'key', | ||
projectId: 'my-project', | ||
appId: 'my-appid', | ||
}, | ||
} as ReactNativeFirebase.FirebaseApp, | ||
backend: new GoogleAIBackend(), | ||
location: 'us-central1', | ||
}; | ||
|
||
describe('API tests', () => { | ||
describe('getGenerativeModel() with VertexAIBackend', () => { | ||
it('should throw an error if no model is provided', () => { | ||
try { | ||
getGenerativeModel(fakeAI, {} as ModelParams); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_MODEL); | ||
expect((e as AIError).message).toContain( | ||
`AI: Must provide a model name. Example: ` + | ||
`getGenerativeModel({ model: 'my-model-name' }) (${AI_TYPE}/${AIErrorCode.NO_MODEL})`, | ||
); | ||
} | ||
}); | ||
|
||
it('getGenerativeModel throws if no apiKey is provided', () => { | ||
const fakeVertexNoApiKey = { | ||
...fakeAI, | ||
app: { options: { projectId: 'my-project', appId: 'my-appid' } }, | ||
} as AI; | ||
try { | ||
getGenerativeModel(fakeVertexNoApiKey, { model: 'my-model' }); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_API_KEY); | ||
expect((e as AIError).message).toBe( | ||
`AI: The "apiKey" field is empty in the local ` + | ||
`Firebase config. Firebase AI requires this field to` + | ||
` contain a valid API key. (${AI_TYPE}/${AIErrorCode.NO_API_KEY})`, | ||
); | ||
} | ||
}); | ||
|
||
it('should throw an error if no projectId is provided', () => { | ||
const fakeVertexNoProject = { | ||
...fakeAI, | ||
app: { options: { apiKey: 'my-key' } }, | ||
} as AI; | ||
try { | ||
getGenerativeModel(fakeVertexNoProject, { model: 'my-model' }); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_PROJECT_ID); | ||
expect((e as AIError).message).toBe( | ||
`AI: The "projectId" field is empty in the local` + | ||
` Firebase config. Firebase AI requires this field ` + | ||
`to contain a valid project ID. (${AI_TYPE}/${AIErrorCode.NO_PROJECT_ID})`, | ||
); | ||
} | ||
}); | ||
|
||
it('should throw an error if no appId is provided', () => { | ||
const fakeVertexNoAppId = { | ||
...fakeAI, | ||
app: { options: { apiKey: 'my-key', projectId: 'my-projectid' } }, | ||
} as AI; | ||
try { | ||
getGenerativeModel(fakeVertexNoAppId, { model: 'my-model' }); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_APP_ID); | ||
expect((e as AIError).message).toBe( | ||
`AI: The "appId" field is empty in the local` + | ||
` Firebase config. Firebase AI requires this field ` + | ||
`to contain a valid app ID. (${AI_TYPE}/${AIErrorCode.NO_APP_ID})`, | ||
); | ||
} | ||
}); | ||
|
||
it('should return an instance of GenerativeModel', () => { | ||
const genModel = getGenerativeModel(fakeAI, { model: 'my-model' }); | ||
expect(genModel).toBeInstanceOf(GenerativeModel); | ||
expect(genModel.model).toBe('publishers/google/models/my-model'); | ||
}); | ||
}); | ||
|
||
describe('getGenerativeModel() with GoogleAIBackend', () => { | ||
it('should throw an error if no model is provided', () => { | ||
try { | ||
getGenerativeModel(fakeGoogleAI, {} as ModelParams); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_MODEL); | ||
expect((e as AIError).message).toContain( | ||
`AI: Must provide a model name. Example: ` + | ||
`getGenerativeModel({ model: 'my-model-name' }) (${AI_TYPE}/${AIErrorCode.NO_MODEL})`, | ||
); | ||
} | ||
}); | ||
|
||
it('getGenerativeModel throws if no apiKey is provided', () => { | ||
const fakeGoogleNoApiKey = { | ||
...fakeGoogleAI, | ||
app: { options: { projectId: 'my-project', appId: 'my-appid' } }, | ||
} as AI; | ||
try { | ||
getGenerativeModel(fakeGoogleNoApiKey, { model: 'my-model' }); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_API_KEY); | ||
expect((e as AIError).message).toBe( | ||
`AI: The "apiKey" field is empty in the local ` + | ||
`Firebase config. Firebase AI requires this field to` + | ||
` contain a valid API key. (${AI_TYPE}/${AIErrorCode.NO_API_KEY})`, | ||
); | ||
} | ||
}); | ||
|
||
it('should throw an error if no projectId is provided', () => { | ||
const fakeGoogleNoProject = { | ||
...fakeGoogleAI, | ||
app: { options: { apiKey: 'my-key' } }, | ||
} as AI; | ||
try { | ||
getGenerativeModel(fakeGoogleNoProject, { model: 'my-model' }); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_PROJECT_ID); | ||
expect((e as AIError).message).toBe( | ||
`AI: The "projectId" field is empty in the local` + | ||
` Firebase config. Firebase AI requires this field ` + | ||
`to contain a valid project ID. (${AI_TYPE}/${AIErrorCode.NO_PROJECT_ID})`, | ||
); | ||
} | ||
}); | ||
|
||
it('should throw an error if no appId is provided', () => { | ||
const fakeGoogleNoAppId = { | ||
...fakeGoogleAI, | ||
app: { options: { apiKey: 'my-key', projectId: 'my-projectid' } }, | ||
} as AI; | ||
try { | ||
getGenerativeModel(fakeGoogleNoAppId, { model: 'my-model' }); | ||
} catch (e) { | ||
expect((e as AIError).code).toContain(AIErrorCode.NO_APP_ID); | ||
expect((e as AIError).message).toBe( | ||
`AI: The "appId" field is empty in the local` + | ||
` Firebase config. Firebase AI requires this field ` + | ||
`to contain a valid app ID. (${AI_TYPE}/${AIErrorCode.NO_APP_ID})`, | ||
); | ||
} | ||
}); | ||
|
||
it('should return an instance of GenerativeModel', () => { | ||
const genModel = getGenerativeModel(fakeGoogleAI, { model: 'my-model' }); | ||
expect(genModel).toBeInstanceOf(GenerativeModel); | ||
expect(genModel.model).toBe('models/my-model'); | ||
}); | ||
}); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/** | ||
* @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 { describe, it, expect } from '@jest/globals'; | ||
import { GoogleAIBackend, VertexAIBackend } from '../lib/backend'; | ||
import { BackendType } from '../lib/public-types'; | ||
import { DEFAULT_LOCATION } from '../lib/constants'; | ||
|
||
describe('Backend', () => { | ||
describe('GoogleAIBackend', () => { | ||
it('should set backendType to GOOGLE_AI', () => { | ||
const backend = new GoogleAIBackend(); | ||
expect(backend.backendType).toBe(BackendType.GOOGLE_AI); | ||
}); | ||
}); | ||
|
||
describe('VertexAIBackend', () => { | ||
it('should set backendType to VERTEX_AI', () => { | ||
const backend = new VertexAIBackend(); | ||
expect(backend.backendType).toBe(BackendType.VERTEX_AI); | ||
expect(backend.location).toBe(DEFAULT_LOCATION); | ||
}); | ||
|
||
it('should set a custom location', () => { | ||
const backend = new VertexAIBackend('test-location'); | ||
expect(backend.backendType).toBe(BackendType.VERTEX_AI); | ||
expect(backend.location).toBe('test-location'); | ||
}); | ||
|
||
it('should use a default location if location is empty string', () => { | ||
const backend = new VertexAIBackend(''); | ||
expect(backend.backendType).toBe(BackendType.VERTEX_AI); | ||
expect(backend.location).toBe(DEFAULT_LOCATION); | ||
}); | ||
|
||
it('uses default location if location is null', () => { | ||
const backend = new VertexAIBackend(null as any); | ||
expect(backend.backendType).toBe(BackendType.VERTEX_AI); | ||
expect(backend.location).toBe(DEFAULT_LOCATION); | ||
}); | ||
}); | ||
}); |
File renamed without changes.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.