Skip to content

Commit

Permalink
contracts component (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonborisoff authored Mar 4, 2024
1 parent fd103d8 commit a1cdebe
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 0 deletions.
Empty file.
15 changes: 15 additions & 0 deletions src/app/components/contracts/contracts.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="componentBorder">
<div>{{'contracts.CONTRACT_LIST_LABEL' | transloco}}</div>
<div data-id="contractList">
@for (contract of contracts; track contract.id) {
<div [attr.data-id]="'contract-' + contract.id">
<h4 data-id="contractNumber">{{contract.number}}</h4>
<h5>{{'contracts.CONDITIONS_LABEL' | transloco}}</h5>
<div data-id="contractConditions">{{contract.conditions}}</div>
</div>
}
</div>
@if(!contracts.length) {
<div data-id="noContractsMessage">{{'contracts.NO_CONTRACTS_LABEL' | transloco}}</div>
}
</div>
61 changes: 61 additions & 0 deletions src/app/components/contracts/contracts.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
Component
} from '@angular/core'
import {
Translation,
TranslocoPipe,
TranslocoService,
provideTranslocoScope
} from '@ngneat/transloco'
import {
getTranslocoInlineLoader
} from '../../../transloco/transloco-loaders'
import {
Contract
} from '../../interfaces/contract'
import {
CommonModule
} from '@angular/common'
import {
ContractService
} from '../../services/contracts/contract.service'
import {
MessageBoxService
} from '../../services/message-box/message-box.service'

const COMPONENT_TRANSLOCO_SCOPE = 'contracts'
@Component({
selector: 'app-contracts',
standalone: true,
imports: [
TranslocoPipe,
CommonModule
],
templateUrl: './contracts.component.html',
styleUrl: './contracts.component.css',
providers: [provideTranslocoScope({
scope: COMPONENT_TRANSLOCO_SCOPE,
loader: getTranslocoInlineLoader((lang: string) => (): Promise<Translation> => import(`./i18n/${lang}.json`))
})]
})
export class ContractsComponent {
public static getTranslocoScope(): string {
return COMPONENT_TRANSLOCO_SCOPE
}

public contracts: Contract[] = []
public constructor(
private contracts$: ContractService,
private translocoService: TranslocoService,
private messageBox: MessageBoxService
) {
this.contracts$.getContracts().subscribe({
next: (contracts) => {
this.contracts = contracts
},
error: () => {
this.messageBox.error(this.translocoService.translate(`${COMPONENT_TRANSLOCO_SCOPE}.GENERAL_ERROR_MESSAGE`))
}
})
}
}
6 changes: 6 additions & 0 deletions src/app/components/contracts/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"CONTRACT_LIST_LABEL": "Contracts:",
"CONDITIONS_LABEL": "Conditions:",
"NO_CONTRACTS_LABEL": "No contracts available",
"GENERAL_ERROR_MESSAGE": "Something went wrong."
}
6 changes: 6 additions & 0 deletions src/app/components/contracts/i18n/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"CONTRACT_LIST_LABEL": "Контракты:",
"CONDITIONS_LABEL": "Условия:",
"NO_CONTRACTS_LABEL": "Нет доступных контрактов",
"GENERAL_ERROR_MESSAGE": "Что-то пошло не так."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {
BaseHarness
} from '../../../tests/foundation/base.component.harness'

export class ContractsHarness extends BaseHarness {
public static hostSelector = 'app-contracts'
}
109 changes: 109 additions & 0 deletions src/app/components/contracts/tests/contracts.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
TestBed
} from '@angular/core/testing'

import {
ContractsComponent
} from '../contracts.component'
import {
getTranslocoTestingModule
} from '../../../../transloco/transloco-testing'
import en from '../i18n/en.json'
import {
ContractService
} from '../../../services/contracts/contract.service'
import {
Contract
} from '../../../interfaces/contract'
import {
of,
throwError
} from 'rxjs'
import {
TestbedHarnessEnvironment
} from '@angular/cdk/testing/testbed'
import {
ContractsHarness
} from './contracts.component.harness'
import {
MessageBoxService
} from '../../../services/message-box/message-box.service'

describe('ContractsComponent', () => {
let contractServiceMock: jasmine.SpyObj<ContractService>
let messageBoxServiceMock: jasmine.SpyObj<MessageBoxService>
let contractsHarness: ContractsHarness

async function initComponent(contracts?: Contract[]): Promise<ContractsHarness> {
if (contracts) {
contractServiceMock.getContracts.and.returnValue(of(contracts))
}
else {
contractServiceMock.getContracts.and.callFake(() => {
return throwError(() => new Error())
})
}

await TestBed.configureTestingModule({
imports: [
ContractsComponent,
getTranslocoTestingModule(ContractsComponent, en)
],
providers: [
{
provide: ContractService,
useValue: contractServiceMock
},
{
provide: MessageBoxService,
useValue: messageBoxServiceMock
}
]
}).compileComponents()

const fixture = TestBed.createComponent(ContractsComponent)
contractsHarness = await TestbedHarnessEnvironment.harnessForFixture(fixture, ContractsHarness)
return contractsHarness
}

beforeEach(async () => {
contractServiceMock = jasmine.createSpyObj<ContractService>('contracts', ['getContracts'])
messageBoxServiceMock = jasmine.createSpyObj<MessageBoxService>('messageBoxService', ['error'])
})

it('display list of contracts', async () => {
const CONTRACTS: Contract[] = [
{
id: 'test_a',
number: 'TESTA',
conditions: 'test contract a'
},
{
id: 'test_b',
number: 'TESTB',
conditions: 'test contract b'
}
]
await initComponent(CONTRACTS)

expect(await contractsHarness.elementChildCount('contractList')).toBe(CONTRACTS.length)
expect(await contractsHarness.elementVisible('noContractsMessage')).toBe(false)
for (const contract of CONTRACTS) {
expect(await contractsHarness.inElement(`contract-${contract.id}`).elementText('contractNumber')).toBe(contract.number)
expect(await contractsHarness.inElement(`contract-${contract.id}`).elementText('contractConditions')).toBe(contract.conditions)
}
})

it('display no contract message if there are no contracts', async () => {
await initComponent([])

expect(await contractsHarness.elementChildCount('contractList')).toBe(0)
expect(await contractsHarness.elementVisible('noContractsMessage')).toBe(true)
})

it('display translated general error if something goes wrong during contract fetch', async () => {
await initComponent()

expect(messageBoxServiceMock.error).toHaveBeenCalledWith('Something went wrong.')
})
})
8 changes: 8 additions & 0 deletions src/app/tests/foundation/tests/test.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ describe('Base harness', () => {
await expectAsync(baseHarness.elementChildCount('div-child-count-grandchild-present-non-existent')).toBeRejected()
})

it('elementChildCount', async () => {
await expectAsync(baseHarness.elementChildCount('div-child-count-no-grandchild-present')).toBeResolvedTo(2)
await expectAsync(baseHarness.elementChildCount('div-child-count-grandchild-present')).toBeResolvedTo(2)

await expectAsync(baseHarness.elementChildCount('div-child-count-no-grandchild-present-non-existent')).toBeRejected()
await expectAsync(baseHarness.elementChildCount('div-child-count-grandchild-present-non-existent')).toBeRejected()
})

it('enterValue - updateOn: change', async () => {
let formValuesOnChange: string[] = []
testComponent.formControlUpdateOnChange.valueChanges.subscribe((value: string) => {
Expand Down

0 comments on commit a1cdebe

Please sign in to comment.