Skip to content

test(analytics): migrate analytics to Vitest - #10375

Open
Manvi1203 wants to merge 2 commits into
mainfrom
feature/vitest-analytics
Open

Manvi1203 wants to merge 2 commits into
mainfrom
feature/vitest-analytics

Conversation

@Manvi1203

Copy link
Copy Markdown
Contributor

Description

Migrates @firebase/analytics unit tests from legacy Karma & Mocha/Chai/Sinon to native Vitest.

Testing & Verification

  • Unit tests (browser): 6 passed (6), 86 passed (86) in ~2.1s total duration

@Manvi1203
Manvi1203 requested review from a team and hsubox76 as code owners September 11, 2026 02:00
@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 0fd29e6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request migrates the @firebase/analytics test suite from Karma, Mocha, Chai, and Sinon to Vitest, updating package scripts, assertions, and mocking utilities across multiple test files. The review feedback points out that the test:integration script in package.json still references Karma despite the integration tests being migrated, and identifies a leftover asynchronous mock call in api.test.ts. Additionally, several test assertions directly accessing mock.calls are flagged as fragile and should be refactored to use safer Vitest matchers like toHaveBeenCalledWith or explicit call checks.

"test:all": "vitest run",
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:all",
"test:browser": "karma start --nocache",
"test:browser": "vitest run --project=browser",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The 'test:integration' script on line 31 still points to Karma ('karma start ./karma.integration.conf.js --nocache'), but the integration test file 'packages/analytics/testing/integration-tests/integration.ts' has been migrated to use Vitest imports ('import { expect, vi } from "vitest"'). Running this script under Karma will now fail because Karma/Webpack cannot resolve or execute Vitest APIs.\n\nPlease update the 'test:integration' script to run via Vitest, or ensure it is covered by 'vitest run'.

Comment on lines 62 to 70
afterEach(async () => {
await initStub();
initStub.restore();
await mockInitializeAnalytics();
mockInitializeAnalytics.mockReset();
_setWrappedGtagFunction(undefined);
wrappedGtag.mockReset();
if (app) {
return deleteApp(app);
}
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In the 'afterEach' hook, calling 'await mockInitializeAnalytics();' is unnecessary and can be safely removed. This is likely a leftover from the legacy Sinon stub migration where 'await initStub()' was used.

  afterEach(async () => {\n    mockInitializeAnalytics.mockReset();\n    _setWrappedGtagFunction(undefined);\n    wrappedGtag.mockReset();\n    if (app) {\n      return deleteApp(app);\n    }\n  });

await fetchDynamicConfigWithRetry(app);
expect(consoleStub.args[0][1]).to.include(fakeMeasurementId);
consoleStub.restore();
expect(consoleStub.mock.calls[0][1]).toContain(fakeMeasurementId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing 'consoleStub.mock.calls[0][1]' directly is fragile because if 'console.warn' is not called, 'calls[0]' will be 'undefined', resulting in a 'TypeError' rather than a descriptive assertion failure. It is better to use 'expect(consoleStub).toHaveBeenCalledWith(...)' for a cleaner and more robust assertion, consistent with other tests in this file.

      expect(consoleStub).toHaveBeenCalledWith(\n        expect.anything(),\n        expect.stringContaining(fakeMeasurementId)\n      );

Comment on lines +196 to +198
expect(consoleStub.mock.calls[0][1]).toContain(fakeMeasurementId);
expect(consoleStub.mock.calls[0][1]).toContain('old-measurement-id');
expect(consoleStub.mock.calls[0][1]).toContain('does not match');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing 'consoleStub.mock.calls[0][1]' directly is fragile because if 'console.warn' is not called, 'calls[0]' will be 'undefined', resulting in a 'TypeError' rather than a descriptive assertion failure. Adding 'expect(consoleStub).toHaveBeenCalled();' first ensures a clear assertion failure if the warning is not logged.

    expect(consoleStub).toHaveBeenCalled();\n    const warningMessage = consoleStub.mock.calls[0][1];\n    expect(warningMessage).toContain(fakeMeasurementId);\n    expect(warningMessage).toContain('old-measurement-id');\n    expect(warningMessage).toContain('does not match');

Comment on lines +221 to +224
expect(warnStub.mock.calls[0][1]).toContain(
AnalyticsError.INVALID_ANALYTICS_CONTEXT
);
expect(warnStub.args[0][1]).to.include('Cookies');
cookieStub.restore();
expect(warnStub.mock.calls[0][1]).toContain('Cookies');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing 'warnStub.mock.calls[0][1]' directly is fragile because if 'console.warn' is not called, 'calls[0]' will be 'undefined', resulting in a 'TypeError' rather than a descriptive assertion failure. Adding 'expect(warnStub).toHaveBeenCalled();' first ensures a clear assertion failure if the warning is not logged.

      expect(warnStub).toHaveBeenCalled();\n      const warningMessage = warnStub.mock.calls[0][1];\n      expect(warningMessage).toContain(\n        AnalyticsError.INVALID_ANALYTICS_CONTEXT\n      );\n      expect(warningMessage).toContain('Cookies');

Comment on lines +67 to 70
const warnStub = vi.spyOn(console, 'warn').mockImplementation(() => {
expect(warnStub.mock.calls[0][1]).toContain('does not match');
done();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing 'warnStub.mock.calls[0][1]' inside the mock implementation itself is fragile. It is cleaner and more robust to use the arguments passed directly to the mock implementation function.

      const warnStub = vi.spyOn(console, 'warn').mockImplementation((_tag, message) => {\n        expect(message).toContain('does not match');\n        done();\n      });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant