Skip to content

Commit aad6b76

Browse files
guguclaude
andcommitted
fix: update test dialog mocking patterns for Vitest compatibility
- Add Angulartics2Module.forRoot() to ForeignKeyFilterComponent tests - Fix router mock in DbConnectionDeleteDialogComponent tests (add events Subject) - Replace vi.spyOn(dialog, 'open') with provider-level MatDialog mocks - Create mocks before TestBed.configureTestingModule for proper injection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 63e1eb2 commit aad6b76

10 files changed

Lines changed: 1400 additions & 26 deletions

File tree

docs/specs/frontend-secret-management.md

Lines changed: 1318 additions & 0 deletions
Large diffs are not rendered by default.

frontend/src/app/components/connect-db/connect-db.component.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { DbConnectionDeleteDialogComponent } from './db-connection-delete-dialog
2222
describe('ConnectDBComponent', () => {
2323
let component: ConnectDBComponent;
2424
let fixture: ComponentFixture<ConnectDBComponent>;
25-
let dialog: MatDialog;
25+
let mockMatDialog: { open: ReturnType<typeof vi.fn> };
2626

2727
const fakeNotifications = {
2828
showErrorSnackbar: vi.fn(),
@@ -63,6 +63,8 @@ describe('ConnectDBComponent', () => {
6363
};
6464

6565
beforeEach(async () => {
66+
mockMatDialog = { open: vi.fn() };
67+
6668
await TestBed.configureTestingModule({
6769
imports: [
6870
MatSnackBarModule,
@@ -85,14 +87,14 @@ describe('ConnectDBComponent', () => {
8587
},
8688
{ provide: NotificationsService, useValue: fakeNotifications },
8789
{ provide: ConnectionsService, useValue: fakeConnectionsService },
90+
{ provide: MatDialog, useValue: mockMatDialog },
8891
],
8992
}).compileComponents();
9093
});
9194

9295
beforeEach(() => {
9396
fixture = TestBed.createComponent(ConnectDBComponent);
9497
component = fixture.componentInstance;
95-
dialog = TestBed.inject(MatDialog);
9698

9799
// @ts-expect-error
98100
global.window.fbq = vi.fn();
@@ -161,11 +163,10 @@ describe('ConnectDBComponent', () => {
161163
});
162164

163165
it('should open delete connection dialog', () => {
164-
const fakeDialogOpen = vi.spyOn(dialog, 'open');
165166
const event = { preventDefault: vi.fn(), stopImmediatePropagation: vi.fn() } as unknown as Event;
166167

167168
component.confirmDeleteConnection(connectionCredsApp, event);
168-
expect(fakeDialogOpen).toHaveBeenCalledWith(DbConnectionDeleteDialogComponent, {
169+
expect(mockMatDialog.open).toHaveBeenCalledWith(DbConnectionDeleteDialogComponent, {
169170
width: '32em',
170171
data: connectionCredsApp,
171172
});
@@ -239,12 +240,11 @@ describe('ConnectDBComponent', () => {
239240
});
240241

241242
it('should open dialog on test error', () => {
242-
const fakeDialogOpen = vi.spyOn(dialog, 'open');
243243
vi.spyOn(component, 'db', 'get').mockReturnValue(connectionCredsApp);
244244
component.masterKey = 'master_password_12345678';
245245
component.handleConnectionError('Hostname is invalid');
246246

247-
expect(fakeDialogOpen).toHaveBeenCalledWith(DbConnectionConfirmDialogComponent, {
247+
expect(mockMatDialog.open).toHaveBeenCalledWith(DbConnectionConfirmDialogComponent, {
248248
width: '25em',
249249
data: {
250250
dbCreds: connectionCredsApp,

frontend/src/app/components/connect-db/db-connection-delete-dialog/db-connection-delete-dialog.component.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { MatRadioModule } from '@angular/material/radio';
66
import { MatSnackBarModule } from '@angular/material/snack-bar';
77
import { provideRouter, Router } from '@angular/router';
88
import { Angulartics2, Angulartics2Module } from 'angulartics2';
9-
import { of } from 'rxjs';
9+
import { of, Subject } from 'rxjs';
1010
import { ConnectionsService } from 'src/app/services/connections.service';
1111
import { DbConnectionDeleteDialogComponent } from './db-connection-delete-dialog.component';
1212

@@ -21,7 +21,7 @@ describe('DbConnectionDeleteDialogComponent', () => {
2121
};
2222

2323
beforeEach(async (): Promise<void> => {
24-
routerSpy = { navigate: vi.fn() };
24+
routerSpy = { navigate: vi.fn(), events: new Subject() };
2525

2626
await TestBed.configureTestingModule({
2727
imports: [

frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.spec.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ describe('DbTableActionsComponent', () => {
1919
let component: DbTableActionsComponent;
2020
let fixture: ComponentFixture<DbTableActionsComponent>;
2121
let tablesService: TablesService;
22-
let dialog: MatDialog;
22+
let mockMatDialog: { open: ReturnType<typeof vi.fn> };
2323
let fakeNotifications;
2424

2525
beforeEach(async () => {
2626
fakeNotifications = {
2727
showSuccessSnackbar: vi.fn(),
2828
};
29+
mockMatDialog = { open: vi.fn() };
2930

3031
await TestBed.configureTestingModule({
3132
imports: [
@@ -42,6 +43,7 @@ describe('DbTableActionsComponent', () => {
4243
provide: NotificationsService,
4344
useValue: fakeNotifications,
4445
},
46+
{ provide: MatDialog, useValue: mockMatDialog },
4547
],
4648
})
4749
.overrideComponent(DbTableActionsComponent, {
@@ -52,7 +54,6 @@ describe('DbTableActionsComponent', () => {
5254

5355
fixture = TestBed.createComponent(DbTableActionsComponent);
5456
tablesService = TestBed.inject(TablesService);
55-
dialog = TestBed.inject(MatDialog);
5657
component = fixture.componentInstance;
5758
fixture.detectChanges();
5859
});
@@ -374,8 +375,6 @@ describe('DbTableActionsComponent', () => {
374375
});
375376

376377
it('should open dialog for delete action confirmation', () => {
377-
const fakeConfirmationDialog = vi.spyOn(dialog, 'open');
378-
379378
const mockRule = {
380379
id: '',
381380
title: 'rule 2',
@@ -389,7 +388,7 @@ describe('DbTableActionsComponent', () => {
389388

390389
component.openDeleteRuleDialog();
391390

392-
expect(fakeConfirmationDialog).toHaveBeenCalledWith(ActionDeleteDialogComponent, {
391+
expect(mockMatDialog.open).toHaveBeenCalledWith(ActionDeleteDialogComponent, {
393392
width: '25em',
394393
data: {
395394
connectionID: '12345678',

frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.spec.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe('DbTableWidgetsComponent', () => {
2323
let fixture: ComponentFixture<DbTableWidgetsComponent>;
2424
let tablesService: TablesService;
2525
let connectionsService: ConnectionsService;
26-
let dialog: MatDialog;
26+
let mockMatDialog: { open: ReturnType<typeof vi.fn> };
2727
const dialogRefSpyObj = {
2828
afterClosed: vi.fn().mockReturnValue(of('delete')),
2929
close: vi.fn(),
@@ -104,7 +104,11 @@ describe('DbTableWidgetsComponent', () => {
104104
Angulartics2Module.forRoot(),
105105
DbTableWidgetsComponent,
106106
],
107-
providers: [provideHttpClient(), { provide: MatDialogRef, useValue: {} }],
107+
providers: [
108+
provideHttpClient(),
109+
{ provide: MatDialogRef, useValue: {} },
110+
{ provide: MatDialog, useFactory: () => mockMatDialog },
111+
],
108112
})
109113
.overrideComponent(WidgetComponent, {
110114
remove: { imports: [CodeEditorModule] },
@@ -122,11 +126,11 @@ describe('DbTableWidgetsComponent', () => {
122126
});
123127

124128
beforeEach(() => {
129+
mockMatDialog = { open: vi.fn() };
125130
fixture = TestBed.createComponent(DbTableWidgetsComponent);
126131
component = fixture.componentInstance;
127132
tablesService = TestBed.inject(TablesService);
128133
connectionsService = TestBed.inject(ConnectionsService);
129-
dialog = TestBed.inject(MatDialog);
130134
fixture.detectChanges();
131135
});
132136

@@ -206,10 +210,10 @@ describe('DbTableWidgetsComponent', () => {
206210
},
207211
];
208212

209-
const fakeDialog = vi.spyOn(dialog, 'open').mockReturnValue(dialogRefSpyObj as any);
213+
mockMatDialog.open.mockReturnValue(dialogRefSpyObj as any);
210214
component.openDeleteWidgetDialog('user_name');
211215

212-
expect(fakeDialog).toHaveBeenCalledWith(WidgetDeleteDialogComponent, {
216+
expect(mockMatDialog.open).toHaveBeenCalledWith(WidgetDeleteDialogComponent, {
213217
width: '25em',
214218
data: 'user_name',
215219
});

frontend/src/app/components/ui-components/filter-fields/foreign-key/foreign-key.component.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { MatDialogModule } from '@angular/material/dialog';
55
import { MatSnackBarModule } from '@angular/material/snack-bar';
66
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
77
import { provideRouter } from '@angular/router';
8+
import { Angulartics2Module } from 'angulartics2';
89
import { of } from 'rxjs';
910
import { TablesService } from 'src/app/services/tables.service';
1011
import { ForeignKeyFilterComponent } from './foreign-key.component';
@@ -126,6 +127,7 @@ describe('ForeignKeyFilterComponent', () => {
126127
MatDialogModule,
127128
ForeignKeyFilterComponent,
128129
BrowserAnimationsModule,
130+
Angulartics2Module.forRoot(),
129131
],
130132
providers: [provideHttpClient(), provideRouter([])],
131133
}).compileComponents();

frontend/src/app/components/user-settings/account-delete-dialog/account-delete-dialog.component.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import { AccountDeleteDialogComponent } from './account-delete-dialog.component'
1212
describe('AccountDeleteDialogComponent', () => {
1313
let component: AccountDeleteDialogComponent;
1414
let fixture: ComponentFixture<AccountDeleteDialogComponent>;
15-
let dialog: MatDialog;
15+
let mockMatDialog: { open: ReturnType<typeof vi.fn> };
1616

1717
const mockDialogRef = {
1818
close: () => {},
1919
};
2020

2121
beforeEach(async () => {
22+
mockMatDialog = { open: vi.fn() };
23+
2224
await TestBed.configureTestingModule({
2325
imports: [
2426
MatDialogModule,
@@ -33,13 +35,13 @@ describe('AccountDeleteDialogComponent', () => {
3335
provideHttpClient(),
3436
{ provide: MAT_DIALOG_DATA, useValue: {} },
3537
{ provide: MatDialogRef, useValue: mockDialogRef },
38+
{ provide: MatDialog, useValue: mockMatDialog },
3639
],
3740
}).compileComponents();
3841
});
3942

4043
beforeEach(() => {
4144
fixture = TestBed.createComponent(AccountDeleteDialogComponent);
42-
dialog = TestBed.inject(MatDialog);
4345
component = fixture.componentInstance;
4446
fixture.detectChanges();
4547
});
@@ -52,10 +54,9 @@ describe('AccountDeleteDialogComponent', () => {
5254
component.reason = 'technical-issues';
5355
component.message = 'I cannot add connection';
5456

55-
const fakeDeleteUserDialogOpen = vi.spyOn(dialog, 'open');
5657
component.openDeleteConfirmation();
5758

58-
expect(fakeDeleteUserDialogOpen).toHaveBeenCalledWith(AccountDeleteConfirmationComponent, {
59+
expect(mockMatDialog.open).toHaveBeenCalledWith(AccountDeleteConfirmationComponent, {
5960
width: '20em',
6061
data: {
6162
reason: 'technical-issues',

frontend/src/app/components/user-settings/user-settings.component.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ describe('UserSettingsComponent', () => {
2020
let component: UserSettingsComponent;
2121
let fixture: ComponentFixture<UserSettingsComponent>;
2222
let userService: UserService;
23-
let dialog: MatDialog;
23+
let mockMatDialog: { open: ReturnType<typeof vi.fn> };
2424

2525
beforeEach(async () => {
26+
mockMatDialog = { open: vi.fn() };
27+
2628
await TestBed.configureTestingModule({
2729
imports: [
2830
RouterTestingModule,
@@ -42,6 +44,7 @@ describe('UserSettingsComponent', () => {
4244
useExisting: forwardRef(() => UserSettingsComponent),
4345
multi: true,
4446
},
47+
{ provide: MatDialog, useValue: mockMatDialog },
4548
],
4649
}).compileComponents();
4750
});
@@ -50,7 +53,6 @@ describe('UserSettingsComponent', () => {
5053
fixture = TestBed.createComponent(UserSettingsComponent);
5154
component = fixture.componentInstance;
5255
userService = TestBed.inject(UserService);
53-
dialog = TestBed.inject(MatDialog);
5456
fixture.detectChanges();
5557
});
5658

@@ -68,7 +70,6 @@ describe('UserSettingsComponent', () => {
6870
});
6971

7072
it('should open delete account dialog', () => {
71-
const fakeDeleteAccountOpen = vi.spyOn(dialog, 'open');
7273
component.currentUser = {
7374
id: 'user-12345678',
7475
createdAt: '2021-10-01T13:43:02.034Z',
@@ -85,7 +86,7 @@ describe('UserSettingsComponent', () => {
8586
};
8687

8788
component.confirmDeleteAccount();
88-
expect(fakeDeleteAccountOpen).toHaveBeenCalledWith(AccountDeleteDialogComponent, {
89+
expect(mockMatDialog.open).toHaveBeenCalledWith(AccountDeleteDialogComponent, {
8990
width: '32em',
9091
data: {
9192
id: 'user-12345678',
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Component, EventEmitter, Input, Output } from '@angular/core';
2+
3+
/**
4+
* Mock component for ngs-code-editor from @ngstack/code-editor.
5+
*
6+
* Usage in tests:
7+
* ```typescript
8+
* import { MockCodeEditorComponent } from 'src/app/testing/code-editor.mock';
9+
* import { CodeEditorModule } from '@ngstack/code-editor';
10+
* import { NO_ERRORS_SCHEMA } from '@angular/core';
11+
*
12+
* await TestBed.configureTestingModule({
13+
* imports: [YourComponent, BrowserAnimationsModule],
14+
* })
15+
* .overrideComponent(YourComponent, {
16+
* remove: { imports: [CodeEditorModule] },
17+
* add: { imports: [MockCodeEditorComponent], schemas: [NO_ERRORS_SCHEMA] }
18+
* })
19+
* .compileComponents();
20+
* ```
21+
*/
22+
@Component({
23+
selector: 'ngs-code-editor',
24+
template: '<div class="mock-code-editor"></div>',
25+
standalone: true,
26+
})
27+
export class MockCodeEditorComponent {
28+
@Input() theme: string = 'vs';
29+
@Input() codeModel: any;
30+
@Input() options: any;
31+
@Input() readOnly: boolean = false;
32+
@Output() valueChanged = new EventEmitter<string>();
33+
}

frontend/src/test-setup.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference types="vitest/globals" />
2+
import 'zone.js';
3+
import 'zone.js/testing';
4+
import { TestBed } from '@angular/core/testing';
5+
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
6+
import { vi } from 'vitest';
7+
8+
// Initialize Angular testing environment
9+
try {
10+
TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
11+
} catch (e) {
12+
// TestBed already initialized
13+
}
14+
15+
// Expose vi globally for tests that need it
16+
(globalThis as any).vi = vi;

0 commit comments

Comments
 (0)