Skip to content

Commit

Permalink
NAS-128450: Port backup widget to new dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexKarpov98 committed May 8, 2024
1 parent 44660f4 commit 6033b45
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatGridListModule } from '@angular/material/grid-list';
import { Spectator } from '@ngneat/spectator';
import { createComponentFactory } from '@ngneat/spectator/jest';
import { createComponentFactory, mockProvider } from '@ngneat/spectator/jest';
import { format } from 'date-fns-tz';
import { MockComponent } from 'ng-mocks';
import { of } from 'rxjs';
import { DragHandleComponent } from 'app/core/components/drag-handle/drag-handle.component';
import { FakeFormatDateTimePipe } from 'app/core/testing/classes/fake-format-datetime.pipe';
import { MockWebSocketService } from 'app/core/testing/classes/mock-websocket.service';
import { mockAuth } from 'app/core/testing/utils/mock-auth.utils';
import { mockWebSocket, mockCall } from 'app/core/testing/utils/mock-websocket.utils';
import { Direction } from 'app/enums/direction.enum';
import { JobState } from 'app/enums/job-state.enum';
import { CloudSyncTask } from 'app/interfaces/cloud-sync-task.interface';
import { ReplicationTask } from 'app/interfaces/replication-task.interface';
import { RsyncTask } from 'app/interfaces/rsync-task.interface';
import { WidgetResourcesService } from 'app/pages/dashboard/services/widget-resources.service';
import { SlotSize } from 'app/pages/dashboard/types/widget.interface';
import { BackupTaskActionsComponent } from 'app/pages/dashboard/widgets/backup/widget-backup/backup-task-actions/backup-task-actions.component';
import { BackupTaskEmptyComponent } from 'app/pages/dashboard/widgets/backup/widget-backup/backup-task-empty/backup-task-empty.component';
import { BackupTaskTileComponent } from 'app/pages/dashboard/widgets/backup/widget-backup/backup-task-tile/backup-task-tile.component';
Expand Down Expand Up @@ -134,131 +135,190 @@ describe('WidgetBackupComponent', () => {
],
providers: [
mockAuth(),
mockWebSocket([
mockCall('replication.query', []),
mockCall('rsynctask.query', []),
mockCall('cloudsync.query', []),
]),
],
});

function setupTasks(tasks: {
replicationTasks?: ReplicationTask[];
rsyncTasks?: RsyncTask[];
cloudSyncTasks?: CloudSyncTask[];
}): void {
spectator.inject(MockWebSocketService).mockCall('replication.query', tasks.replicationTasks || []);
spectator.inject(MockWebSocketService).mockCall('rsynctask.query', tasks.rsyncTasks || []);
spectator.inject(MockWebSocketService).mockCall('cloudsync.query', tasks.cloudSyncTasks || []);
spectator.component.getBackups();
spectator.detectChanges();
}
describe('first mockup variation', () => {
beforeEach(async () => {
spectator = createComponent({
props: {
size: SlotSize.Full,
},
providers: [
mockProvider(WidgetResourcesService, {
backups$: of([[], [], []]),
}),
],
});

beforeEach(async () => {
spectator = createComponent();
widgetBackup = await TestbedHarnessEnvironment.harnessForFixture(spectator.fixture, WidgetBackupHarness);
});
widgetBackup = await TestbedHarnessEnvironment.harnessForFixture(spectator.fixture, WidgetBackupHarness);
});

it('shows title', async () => {
const header = await widgetBackup.getHeader();
expect(header.title).toBe('Backup Tasks');
});
it('shows title', async () => {
const header = await widgetBackup.getHeader();
expect(header.title).toBe('Backup Tasks');
});

it('hides tiles when no data', async () => {
expect(await widgetBackup.getTiles()).toBeNull();
expect(await widgetBackup.getEmptyCardMessage()).toBe('Backup to Cloud or another TrueNAS via links below');
it('hides tiles when no data', async () => {
expect(await widgetBackup.getTiles()).toBeNull();
expect(await widgetBackup.getEmptyCardMessage()).toBe('Backup to Cloud or another TrueNAS via links below');
});
});

it('shows tiles when data exists', async () => {
setupTasks({ replicationTasks, rsyncTasks, cloudSyncTasks });

expect(await widgetBackup.getEmptyCardMessage()).toBeNull();
expect(await widgetBackup.getBannerMessage()).toBeNull();
describe('second mockup variation', () => {
beforeEach(async () => {
spectator = createComponent({
props: {
size: SlotSize.Full,
},
providers: [
mockProvider(WidgetResourcesService, {
backups$: of([replicationTasks, rsyncTasks, cloudSyncTasks]),
}),
],
});

const tiles = await widgetBackup.getTiles();
expect(tiles).toEqual({
'Cloud Sync': {
firstColumn: ['2 send tasks', '0 receive tasks', 'Total failed: 0'],
secondColumn: ['2 sent tasks this week', '—', `Last successful: ${format(currentDatetime.getTime() - 30000, 'yyyy-MM-dd HH:mm:ss')}`],
},
Replication: {
firstColumn: ['2 send tasks', '1 receive task', 'Total failed: 3'],
secondColumn: ['—', '—', 'Last successful: Never'],
},
Rsync: {
firstColumn: ['1 send task', '2 receive tasks', 'Total failed: 0'],
secondColumn: ['1 sent task this week', '1 received task this week', `Last successful: ${format(currentDatetime.getTime() - 10000, 'yyyy-MM-dd HH:mm:ss')}`],
},
widgetBackup = await TestbedHarnessEnvironment.harnessForFixture(spectator.fixture, WidgetBackupHarness);
});
});

it('shows banner with backup actions below when tasks only received', async () => {
setupTasks({
replicationTasks: [{
id: 1,
direction: Direction.Pull,
state: {
state: JobState.Success,
datetime: { $date: currentDatetime.getTime() - 50000 },
it('shows tiles when data exists', async () => {
expect(await widgetBackup.getEmptyCardMessage()).toBeNull();
expect(await widgetBackup.getBannerMessage()).toBeNull();

const tiles = await widgetBackup.getTiles();
expect(tiles).toEqual({
'Cloud Sync': {
firstColumn: ['2 send tasks', '0 receive tasks', 'Total failed: 0'],
secondColumn: ['2 sent tasks this week', '—', `Last successful: ${format(currentDatetime.getTime() - 30000, 'yyyy-MM-dd HH:mm:ss')}`],
},
Replication: {
firstColumn: ['2 send tasks', '1 receive task', 'Total failed: 3'],
secondColumn: ['—', '—', 'Last successful: Never'],
},
}] as ReplicationTask[],
rsyncTasks: [{
id: 1,
direction: Direction.Pull,
job: {
state: JobState.Success,
time_finished: { $date: currentDatetime.getTime() - 50000 },
Rsync: {
firstColumn: ['1 send task', '2 receive tasks', 'Total failed: 0'],
secondColumn: ['1 sent task this week', '1 received task this week', `Last successful: ${format(currentDatetime.getTime() - 10000, 'yyyy-MM-dd HH:mm:ss')}`],
},
}] as RsyncTask[],
});
});

expect(await widgetBackup.getBackupActionMessages()).toEqual({
Replication: null,
Rsync: null,
it('shows alert status when there are errors', async () => {
const header = await widgetBackup.getHeader();
expect(header.icon).toBe('mdi-alert');
expect(header.message).toBe('3 of 8 tasks failed');
});
expect(await widgetBackup.getBannerMessage()).toBe('Backup to cloud or to another TrueNAS');
});

it('shows backup actions only when one tile has received tasks', async () => {
setupTasks({
replicationTasks: [{
id: 1,
direction: Direction.Pull,
state: {
state: JobState.Success,
datetime: { $date: currentDatetime.getTime() - 50000 },
},
}] as ReplicationTask[],
rsyncTasks: [{
id: 1,
direction: Direction.Push,
job: {
state: JobState.Success,
time_finished: { $date: currentDatetime.getTime() - 50000 },
describe('third mockup variation', () => {
beforeEach(async () => {
spectator = createComponent({
props: {
size: SlotSize.Full,
},
}] as RsyncTask[],
providers: [
mockProvider(WidgetResourcesService, {
backups$: of([
[{
id: 1,
direction: Direction.Pull,
state: {
state: JobState.Success,
datetime: { $date: currentDatetime.getTime() - 50000 },
},
}] as ReplicationTask[],
[{
id: 1,
direction: Direction.Push,
job: {
state: JobState.Success,
time_finished: { $date: currentDatetime.getTime() - 50000 },
},
}] as RsyncTask[],
[],
]),
}),
],
});

widgetBackup = await TestbedHarnessEnvironment.harnessForFixture(spectator.fixture, WidgetBackupHarness);
});

expect(await widgetBackup.getBannerMessage()).toBeNull();
expect(await widgetBackup.getBackupActionMessages()).toEqual({
Replication: 'Backup to cloud or to another TrueNAS',
Rsync: null,
it('shows backup actions only when one tile has received tasks', async () => {
expect(await widgetBackup.getBannerMessage()).toBeNull();
expect(await widgetBackup.getBackupActionMessages()).toEqual({
Replication: 'Backup to cloud or to another TrueNAS',
Rsync: null,
});
});
});

it('shows alert status when there are errors', async () => {
setupTasks({ replicationTasks, rsyncTasks, cloudSyncTasks });
describe('fourth mockup variation', () => {
beforeEach(async () => {
spectator = createComponent({
props: {
size: SlotSize.Full,
},
providers: [
mockProvider(WidgetResourcesService, {
backups$: of([
[{
id: 1,
direction: Direction.Pull,
state: {
state: JobState.Success,
datetime: { $date: currentDatetime.getTime() - 50000 },
},
}],
[{
id: 1,
direction: Direction.Push,
job: {
state: JobState.Success,
time_finished: { $date: currentDatetime.getTime() - 50000 },
},
}] as RsyncTask[],
[],
]),
}),
],
});

widgetBackup = await TestbedHarnessEnvironment.harnessForFixture(spectator.fixture, WidgetBackupHarness);
});

const header = await widgetBackup.getHeader();
expect(header.icon).toBe('mdi-alert');
expect(header.message).toBe('3 of 8 tasks failed');
it('shows backup actions only when one tile has received tasks', async () => {
expect(await widgetBackup.getBannerMessage()).toBeNull();
expect(await widgetBackup.getBackupActionMessages()).toEqual({
Replication: 'Backup to cloud or to another TrueNAS',
Rsync: null,
});
});
});

it('shows success status when there are no errors', async () => {
setupTasks({ cloudSyncTasks });
describe('fifth mockup variation', () => {
beforeEach(async () => {
spectator = createComponent({
props: {
size: SlotSize.Full,
},
providers: [
mockProvider(WidgetResourcesService, {
backups$: of([
[],
[],
cloudSyncTasks,
]),
}),
],
});

widgetBackup = await TestbedHarnessEnvironment.harnessForFixture(spectator.fixture, WidgetBackupHarness);
});

const header = await widgetBackup.getHeader();
expect(header.icon).toBe('mdi-check-circle');
expect(header.message).toBeFalsy();
it('shows success status when there are no errors', async () => {
const header = await widgetBackup.getHeader();
expect(header.icon).toBe('mdi-check-circle');
expect(header.message).toBeFalsy();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export class WidgetBackupHarness extends ComponentHarness {
static hostSelector = 'ix-widget-backup';

async getHeader(): Promise<{ title: string; icon: string; message: string }> {
const title = await this.locatorForOptional('.card-title-text')();
const title = await this.locatorForOptional('.title h3')();
const icon = await this.locatorForOptional(IxIconHarness.with({ selector: '.icon' }))();
const message = await this.locatorForOptional('.status-container')();
return {
Expand All @@ -21,7 +21,7 @@ export class WidgetBackupHarness extends ComponentHarness {
}

async getEmptyCardMessage(): Promise<string | null> {
const message = await this.locatorForOptional('.empty-card-content > .backup-actions')();
const message = await this.locatorForOptional('.empty-card-content .backup-actions')();
return message ? (await message.text()).trim() : null;
}

Expand Down

0 comments on commit 6033b45

Please sign in to comment.