Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { describe, expect, it } from '@jest/globals';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { mount, NgxTestWrapper } from '../../../../../testing';
import { mock, mount, NgxTestWrapper } from '../../../../../testing';

Choose a reason for hiding this comment

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

medium

The mock utility is imported but is not used within this file. It's good practice to remove unused imports to maintain code cleanliness.

Suggested change
import { mock, mount, NgxTestWrapper } from '../../../../../testing';
import { mount, NgxTestWrapper } from '../../../../../testing';

import { SharedModule } from '../../modules/shared/shared.module';

import { AccountDialogComponent } from './account-dialog.component';
import { apiClient } from '../../services/api/api.service';
import * as externalUtils from '../../utils';

describe('AccountDialogComponent', () => {
let wrapper: NgxTestWrapper<AccountDialogComponent>;
Expand All @@ -25,15 +27,78 @@ describe('AccountDialogComponent', () => {
fixture.detectChanges();
});

beforeEach(() => jest.clearAllMocks());

Comment on lines +30 to +31
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix duplicate test hook (Biome: noDuplicateTestHooks).

Two beforeEach hooks in the same describe block violate the linter. Move mock clearing to an afterEach or merge it into the first beforeEach.

Apply this diff:

-  beforeEach(() => jest.clearAllMocks());
+  afterEach(() => {
+    jest.clearAllMocks();
+  });

Additionally, consider avoiding a second component instantiation. Use the wrapper’s instance instead of TestBed.createComponent to reduce flakiness:

// replace:
fixture = TestBed.createComponent(AccountDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();

// with:
component = wrapper.component.componentInstance;
🧰 Tools
🪛 Biome (2.1.2)

[error] 30-30: Disallow duplicate setup and teardown hooks.

Disallow beforeEach duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)

🤖 Prompt for AI Agents
In
packages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.spec.ts
around lines 30-31, there are two beforeEach hooks causing the
noDuplicateTestHooks lint error; move the jest.clearAllMocks() call into an
afterEach (or merge it into the existing beforeEach) to remove the duplicate
hook, and replace the second component instantiation by using the wrapper’s
component instance instead of calling TestBed.createComponent again (i.e., set
the component from wrapper.component.componentInstance and remove
fixture.detectChanges()/recreation to avoid flakiness).

it('should create', () => {
expect(wrapper.component.nativeElement).toMatchSnapshot();
});

it ('should have default showDialog as true', () => {
expect(component.showDialog).toBe(true);
});

it('should have undefined account by default', () => {
expect(component.account).toBeUndefined();
});

it('should emit "handleLoginChange" when login is clicked', () => {
const login = wrapper.find('.btn--primary');

login.emit('click');

expect(wrapper.emitted('handleLoginChange')).toBeTruthy();
});

it('should emit handleLoginChange on submitLogin', () => {
jest.spyOn(component.handleLoginChange, 'emit');
component.submitLogin();
expect(component.handleLoginChange.emit).toHaveBeenCalled();
});

it ('should open billing page with correct URL', async () => {
const mockUrl = 'https://billing.example.com';
jest.spyOn(apiClient, 'getBillingUrl').mockResolvedValue({ url: mockUrl });
const mockEvent = new MouseEvent('click');
const externalSpy = jest.spyOn(externalUtils, 'externalLink').mockImplementation(() => {});

await component.openBillingPage(mockEvent);

expect(apiClient.getBillingUrl).toHaveBeenCalledWith();
expect(externalSpy).toHaveBeenCalledWith(mockUrl, mockEvent);
});

it ('should call getUpgradeProUrl and open external link', async () => {
const mockUrl = 'https://upgrade.example.com';
jest.spyOn(apiClient, 'getUpgradeProUrl').mockResolvedValue({ url: mockUrl });
const mockEvent = new MouseEvent('click');
const externalSpy = jest.spyOn(externalUtils, 'externalLink').mockImplementation(() => {});

await component.openUpgradeProUrl(mockEvent);

expect(apiClient.getUpgradeProUrl).toHaveBeenCalledWith();
expect(externalSpy).toHaveBeenCalledWith(mockUrl, mockEvent);
});

it ('should call buyCredits and open external link if url exists', async () => {
const mockUrl = 'https://credits.example.com';
jest.spyOn(apiClient, 'buyCredits').mockResolvedValue({ url: mockUrl });
const mockEvent = new MouseEvent('click');
const externalSpy = jest.spyOn(externalUtils, 'externalLink').mockImplementation(() => {});

await component.buyCredits(mockEvent);

expect(apiClient.buyCredits).toHaveBeenCalledWith();
expect(externalSpy).toHaveBeenCalledWith(mockUrl, mockEvent);
});
Comment on lines +58 to +92

Choose a reason for hiding this comment

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

medium

These three tests for openBillingPage, openUpgradeProUrl, and buyCredits are very similar in structure. To improve maintainability and reduce code duplication, you could refactor them into a single parameterized test using Jest's it.each.

  it.each([
    { method: 'openBillingPage', api: 'getBillingUrl', url: 'https://billing.example.com' },
    { method: 'openUpgradeProUrl', api: 'getUpgradeProUrl', url: 'https://upgrade.example.com' },
    { method: 'buyCredits', api: 'buyCredits', url: 'https://credits.example.com' },
  ])('should call $api and open external link for $method', async ({ method, api, url }) => {
    jest.spyOn(apiClient, api as keyof typeof apiClient).mockResolvedValue({ url });
    const mockEvent = new MouseEvent('click');
    const externalSpy = jest.spyOn(externalUtils, 'externalLink').mockImplementation(() => {});

    await (component as any)[method](mockEvent);

    expect(apiClient[api as keyof typeof apiClient]).toHaveBeenCalledWith();
    expect(externalSpy).toHaveBeenCalledWith(url, mockEvent);
  });


it('should not call externalLink if buyCredits returns no url', async () => {
jest.spyOn(apiClient, 'buyCredits').mockResolvedValue({ url: '' });
const mockEvent = new MouseEvent('click');
const externalSpy = jest.spyOn(externalUtils, 'externalLink').mockImplementation(() => {});

await component.buyCredits(mockEvent);

expect(apiClient.buyCredits).toHaveBeenCalledWith();
expect(externalSpy).not.toHaveBeenCalled();
});
});