Skip to content
Merged
Show file tree
Hide file tree
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 @@ -5,6 +5,7 @@ import { DbTableRowEditComponent } from './db-table-row-edit.component';
import { MatDialogModule } from '@angular/material/dialog';
import { TablesService } from 'src/app/services/tables.service';
import { ConnectionsService } from 'src/app/services/connections.service';
import { DBtype, Connection, ConnectionType } from 'src/app/models/connection';
import { Angulartics2Module } from 'angulartics2';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter } from '@angular/router';
Expand Down Expand Up @@ -255,4 +256,107 @@ describe('DbTableRowEditComponent', () => {
const isPriceWidget = component.isWidget('Price');
expect(isPriceWidget).toBeTrue();
});

describe('updateField for password widget behavior', () => {
beforeEach(() => {
component.tableRowValues = {
id: 1,
username: 'testuser',
password: '***'
};
});

it('should update tableRowValues when password field receives a value', () => {
component.updateField('newPassword', 'password');
expect(component.tableRowValues['password']).toBe('newPassword');
});

it('should update tableRowValues when password field receives empty string', () => {
component.updateField('', 'password');
expect(component.tableRowValues['password']).toBe('');
});

it('should update tableRowValues when password field receives null (clear password)', () => {
component.updateField(null, 'password');
expect(component.tableRowValues['password']).toBe(null);
});

it('should handle password field update alongside other fields', () => {
component.updateField('updatedUser', 'username');
component.updateField('newPassword', 'password');

expect(component.tableRowValues['username']).toBe('updatedUser');
expect(component.tableRowValues['password']).toBe('newPassword');
});
});

describe('getFormattedUpdatedRow', () => {
beforeEach(() => {
spyOnProperty(connectionsService, 'currentConnection').and.returnValue({
id: 'test-id',
database: 'test-db',
title: 'Test Connection',
host: 'localhost',
port: '5432',
sid: null,
type: DBtype.Postgres,
username: 'test-user',
ssh: false,
ssl: false,
cert: '',
masterEncryption: false,
azure_encryption: false,
connectionType: ConnectionType.Direct
} as Connection);
component.tableTypes = {};
component.nonModifyingFields = [];
component.pageAction = null;
});

it('should include password field when it has a value', () => {
component.tableRowValues = {
id: 1,
username: 'testuser',
password: 'newPassword'
};

const result = component.getFormattedUpdatedRow();
expect((result as any).password).toBe('newPassword');
});

it('should include password field when it is null (explicit clear)', () => {
component.tableRowValues = {
id: 1,
username: 'testuser',
password: null
};

const result = component.getFormattedUpdatedRow();
expect((result as any).password).toBe(null);
});

it('should include password field when it is empty string', () => {
component.tableRowValues = {
id: 1,
username: 'testuser',
password: ''
};

const result = component.getFormattedUpdatedRow();
expect((result as any).password).toBe('');
});

it('should preserve other fields when password is empty', () => {
component.tableRowValues = {
id: 1,
username: 'testuser',
password: ''
};

const result = component.getFormattedUpdatedRow();
expect((result as any).id).toBe(1);
expect((result as any).username).toBe('testuser');
expect((result as any).password).toBe('');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<mat-label>{{normalizedLabel}}</mat-label>
<input matInput type="password" autocomplete="new-password" name="{{label}}-{{key}}"
[required]="required" [disabled]="disabled || clearPassword" [readonly]="readonly"
[(ngModel)]="value" (ngModelChange)="onFieldChange.emit($event)">
[(ngModel)]="value" (ngModelChange)="onPasswordChange($event)">
<mat-hint>To keep password the same keep this field blank.</mat-hint>
</mat-form-field>
<mat-checkbox class="password-checkbox"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,69 @@ describe('PasswordRowComponent', () => {
component.onClearPasswordChange();
expect(event).toHaveBeenCalledWith(null);
});

describe('ngOnInit', () => {
it('should reset masked password value to empty string', () => {
component.value = '***';
component.ngOnInit();
expect(component.value).toBe('');
});

it('should not emit onFieldChange when password is masked (empty after reset)', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.value = '***';
component.ngOnInit();
expect(event).not.toHaveBeenCalled();
});

it('should emit onFieldChange when password has actual value', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.value = 'actualPassword';
component.ngOnInit();
expect(event).toHaveBeenCalledWith('actualPassword');
});

it('should not emit onFieldChange when password is empty string', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.value = '';
component.ngOnInit();
expect(event).not.toHaveBeenCalled();
});
});

describe('onPasswordChange', () => {
it('should emit onFieldChange when password has value', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.onPasswordChange('newPassword');
expect(event).toHaveBeenCalledWith('newPassword');
});

it('should not emit onFieldChange when password is empty string', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.onPasswordChange('');
expect(event).not.toHaveBeenCalled();
});

it('should emit onFieldChange when password is whitespace (actual value)', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.onPasswordChange(' ');
expect(event).toHaveBeenCalledWith(' ');
});
});

describe('onClearPasswordChange', () => {
it('should emit null when clearPassword is true', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.clearPassword = true;
component.onClearPasswordChange();
expect(event).toHaveBeenCalledWith(null);
});

it('should not emit when clearPassword is false', () => {
const event = spyOn(component.onFieldChange, 'emit');
component.clearPassword = false;
component.onClearPasswordChange();
expect(event).not.toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ export class PasswordRowComponent extends BaseRowFieldComponent {
ngOnInit(): void {
super.ngOnInit();
if (this.value === '***') this.value = '';
this.onFieldChange.emit(this.value);
// Don't emit empty password value to skip sending it to backend
if (this.value !== '') {
this.onFieldChange.emit(this.value);
}
}

onPasswordChange(newValue: string) {
// Only emit non-empty values to prevent sending empty strings to backend
if (newValue !== '') {
this.onFieldChange.emit(newValue);
}
}

onClearPasswordChange() {
Expand Down