Skip to content

Commit

Permalink
feat(components/datetime): add methods to the date-range-picker harne…
Browse files Browse the repository at this point in the history
…ss to get the selected calculator, and the start and end date values (#2925)
  • Loading branch information
Blackbaud-SteveBrush authored Dec 4, 2024
1 parent 98fab62 commit 5114b28
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ComponentFixture,
TestBed,
fakeAsync,
flush,
tick,
} from '@angular/core/testing';
import { SkyAppTestUtility, expect, expectAsync } from '@skyux-sdk/testing';
Expand Down Expand Up @@ -466,6 +467,18 @@ describe('Date range picker', function () {
expect(component.numValueChangeNotifications).toEqual(1);
}));

it('should set the calculator ID to the default on initialization', fakeAsync(() => {
fixture.detectChanges();

expect(getCalculatorSelect().value).toEqual(
`${SkyDateRangeCalculatorId.AnyTime}`,
);

// Clear all microtasks since we only care about the state of the component
// before the first change detection cycle.
flush();
}));

it('should use default calculator value if control set to `null`', fakeAsync(function () {
fixture.detectChanges();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ export class SkyDateRangePickerComponent
protected showEndDatePicker = signal<boolean>(false);
protected showStartDatePicker = signal<boolean>(false);

#_calculatorIds = SKY_DEFAULT_CALCULATOR_IDS;
#_label: string | undefined;
#_value = this.selectedCalculator.getValue();

#hostHasCustomError: Signal<boolean | undefined> | undefined;
#notifyChange: ((_: SkyDateRangeCalculation) => void) | undefined;
#notifyTouched: (() => void) | undefined;

Expand All @@ -281,7 +286,6 @@ export class SkyDateRangePickerComponent
#startDateControl = new FormControl<DateValue>(this.#getValue().startDate);
#startDateInvalid = this.#createStatusChangeSignal(this.#startDateControl);
#startDateTouched = this.#createTouchedChangeSignal(this.#startDateControl);
#hostHasCustomError: Signal<boolean | undefined> | undefined;

protected formGroup = inject(FormBuilder).group({
calculatorId: this.#calculatorIdControl,
Expand Down Expand Up @@ -311,10 +315,6 @@ export class SkyDateRangePickerComponent
return calculatorIdHasErrors || (touched && invalid);
});

#_calculatorIds = SKY_DEFAULT_CALCULATOR_IDS;
#_label: string | undefined;
#_value = this.selectedCalculator.getValue();

public ngAfterViewInit(): void {
this.hostControl = this.#injector.get(NgControl, null, {
optional: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { Component } from '@angular/core';
import { Component, inject, signal } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {
FormBuilder,
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import {
SkyDateRangeCalculation,
SkyDateRangeCalculator,
SkyDateRangeCalculatorId,
SkyDateRangeCalculatorType,
SkyDateRangePickerModule,
SkyDateRangeService,
} from '@skyux/datetime';

import { SkyDateRangePickerHarness } from './date-range-picker-harness';
Expand All @@ -23,7 +26,8 @@ import { SkyDateRangePickerHarness } from './date-range-picker-harness';
<form [formGroup]="myForm">
<sky-date-range-picker
data-sky-id="test-date-range-picker"
formControlName="testPicker"
formControlName="pickerControl"
[calculatorIds]="calculatorIds()"
[helpPopoverContent]="helpPopoverContent"
[helpPopoverTitle]="helpPopoverTitle"
[hintText]="hintText"
Expand All @@ -42,18 +46,54 @@ import { SkyDateRangePickerHarness } from './date-range-picker-harness';
`,
})
class TestComponent {
#dateRangeSvc = inject(SkyDateRangeService);

public pickerControl = new FormControl<SkyDateRangeCalculation | undefined>(
undefined,
);

public myForm = inject(FormBuilder).group({
pickerControl: this.pickerControl,
});

public customErrorFlag = false;
public helpPopoverContent: string | undefined;
public helpPopoverTitle: string | undefined;
public hintText: string | undefined;
public labelText: string | undefined;
public myForm: FormGroup;
public stacked = false;

constructor(formBuilder: FormBuilder) {
this.myForm = formBuilder.group({
testPicker: new FormControl(''),
protected calculatorIds = signal<SkyDateRangeCalculatorId[]>(
this.#getCurrentCalculatorIds(),
);

#customCalculator: SkyDateRangeCalculator | undefined;

public createCustomCalculator(): SkyDateRangeCalculatorId {
if (this.#customCalculator) {
throw new Error('Custom calculator already exists.');
}

this.#customCalculator = this.#dateRangeSvc.createCalculator({
shortDescription: 'Since 1999',
type: SkyDateRangeCalculatorType.Relative,
getValue: () => {
return {
startDate: new Date('1/1/1999'),
endDate: new Date(),
};
},
});

this.calculatorIds.set(this.#getCurrentCalculatorIds());

return this.#customCalculator.calculatorId;
}

#getCurrentCalculatorIds(): SkyDateRangeCalculatorId[] {
return this.#dateRangeSvc.calculators.map(
(calculator) => calculator.calculatorId,
);
}
}
//#endregion Test component
Expand Down Expand Up @@ -161,7 +201,7 @@ describe('Date range picker harness', () => {
it('should get whether date range picker is disabled', async () => {
const { dateRangePickerHarness, fixture } = await setupTest();

fixture.componentInstance.myForm.controls['testPicker'].disable();
fixture.componentInstance.pickerControl.disable();
fixture.detectChanges();

await expectAsync(dateRangePickerHarness.isDisabled()).toBeResolvedTo(true);
Expand Down Expand Up @@ -270,19 +310,24 @@ describe('Date range picker harness', () => {
await dateRangePickerHarness.selectCalculator(
SkyDateRangeCalculatorId.SpecificRange,
);

const newDate = new Date('01/12/1997').toLocaleDateString('en-us', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});

await dateRangePickerHarness.setStartDateValue(newDate);
expect(
fixture.componentInstance.myForm.controls['testPicker'].value,
).toEqual({

expect(fixture.componentInstance.pickerControl.value).toEqual({
calculatorId: 3,
startDate: new Date('01/12/1997'),
endDate: null,
});

await expectAsync(
dateRangePickerHarness.getStartDateValue(),
).toBeResolvedTo('01/12/1997');
});

it('should set the end date', async () => {
Expand All @@ -291,34 +336,84 @@ describe('Date range picker harness', () => {
await dateRangePickerHarness.selectCalculator(
SkyDateRangeCalculatorId.SpecificRange,
);

const newDate = new Date('01/12/1997').toLocaleDateString('en-us', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});

await dateRangePickerHarness.setEndDateValue(newDate);
expect(
fixture.componentInstance.myForm.controls['testPicker'].value,
).toEqual({

expect(fixture.componentInstance.pickerControl.value).toEqual({
calculatorId: 3,
endDate: new Date('01/12/1997'),
startDate: null,
});

await expectAsync(dateRangePickerHarness.getEndDateValue()).toBeResolvedTo(
'01/12/1997',
);
});

it('should throw an error if trying to set a date for a hidden datepicker', async () => {
it('should throw an error if trying to get/set a date for a hidden datepicker', async () => {
const { dateRangePickerHarness } = await setupTest();

await expectAsync(
dateRangePickerHarness.getStartDateValue(),
).toBeRejectedWithError(
'Unable to get start date. Start datepicker is not visible.',
);

await expectAsync(
dateRangePickerHarness.setStartDateValue('10/12/2023'),
).toBeRejectedWithError(
'Unable to set start date. Start datepicker is not visible.',
);

await expectAsync(
dateRangePickerHarness.getEndDateValue(),
).toBeRejectedWithError(
'Unable to get end date. End datepicker is not visible.',
);

await expectAsync(
dateRangePickerHarness.setEndDateValue('10/12/2023'),
).toBeRejectedWithError(
'Unable to set end date. End datepicker is not visible.',
);
});

it('should get the selected calculator', async () => {
const { dateRangePickerHarness, fixture } = await setupTest();

// Check the value on initialization.
await expectAsync(
dateRangePickerHarness.getSelectedCalculator(),
).toBeResolvedTo(SkyDateRangeCalculatorId.AnyTime);

// Set the calculator to a specific range.
await dateRangePickerHarness.selectCalculator(
SkyDateRangeCalculatorId.SpecificRange,
);

await expectAsync(
dateRangePickerHarness.getSelectedCalculator(),
).toBeResolvedTo(SkyDateRangeCalculatorId.SpecificRange);

// Set the calculator to an invalid calculator.
await expectAsync(
dateRangePickerHarness.selectCalculator(-1 as SkyDateRangeCalculatorId),
).toBeRejectedWithError('Could not find calculator with ID -1.');

// Set the calculator to a custom calculator.
const customCalculatorId =
fixture.componentInstance.createCustomCalculator();

await dateRangePickerHarness.selectCalculator(customCalculatorId);

await expectAsync(
dateRangePickerHarness.getSelectedCalculator(),
).toBeResolvedTo(customCalculatorId);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ export class SkyDateRangePickerHarness extends SkyComponentHarness {
await (await this.#getCalculatorIdInputBoxHarness()).clickHelpInline();
}

/**
* Gets the end date value.
*/
public async getEndDateValue(): Promise<string> {
if (!(await this.isEndDateVisible())) {
throw new Error('Unable to get end date. End datepicker is not visible.');
}

const input = await (await this.#getEndDatepicker()).getControl();

return await input.getValue();
}

/**
* Gets the help popover content.
*/
Expand Down Expand Up @@ -81,6 +94,37 @@ export class SkyDateRangePickerHarness extends SkyComponentHarness {
return await (await this.#getCalculatorIdInputBoxHarness()).getLabelText();
}

/**
* Gets the selected calculator ID.
*/
public async getSelectedCalculator(): Promise<SkyDateRangeCalculatorId> {
const calculatorIdHarness = await this.#getCalculatorIdInputBoxHarness();
const selectEl = await calculatorIdHarness.querySelector('select');
const value = await selectEl?.getProperty('value');

/* istanbul ignore next: safety check */
if (value === undefined || value === '') {
throw new Error('No calculator selected.');
}

return +value as SkyDateRangeCalculatorId;
}

/**
* Gets the start date value.
*/
public async getStartDateValue(): Promise<string> {
if (!(await this.isStartDateVisible())) {
throw new Error(
'Unable to get start date. Start datepicker is not visible.',
);
}

const input = await (await this.#getStartDatepicker()).getControl();

return await input.getValue();
}

/**
* Whether date range picker end date before start date error is thrown.
*/
Expand Down Expand Up @@ -153,9 +197,28 @@ export class SkyDateRangePickerHarness extends SkyComponentHarness {
calculatorId: SkyDateRangeCalculatorId,
): Promise<void> {
const select = await this.locatorFor(
'select[FormControlName="calculatorId"',
'select[FormControlName="calculatorId"]',
)();
return await select.selectOptions(calculatorId);

const options = await select.getProperty('options');

let optionIndex: number | undefined;

// Find the index of the option with the specified value.
for (let i = 0; i < options.length; i++) {
const option = options[i];

if (`${option.value}` === `${calculatorId}`) {
optionIndex = i;
break;
}
}

if (optionIndex === undefined) {
throw new Error(`Could not find calculator with ID ${calculatorId}.`);
}

await select.selectOptions(optionIndex);
}

/**
Expand Down

0 comments on commit 5114b28

Please sign in to comment.