Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(components/datetime): add methods to the date-range-picker harness to get the selected calculator, and the start and end date values #2925

Merged
merged 7 commits into from
Dec 4, 2024
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 @@ -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(() => {
Blackbaud-SandhyaRajasabeson marked this conversation as resolved.
Show resolved Hide resolved
fixture.detectChanges();

expect(getCalculatorSelect().value).toEqual(
`${SkyDateRangeCalculatorId.AnyTime}`,
Blackbaud-SandhyaRajasabeson marked this conversation as resolved.
Show resolved Hide resolved
);

// 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();
Blackbaud-SteveBrush marked this conversation as resolved.
Show resolved Hide resolved

#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);
Blackbaud-SteveBrush marked this conversation as resolved.
Show resolved Hide resolved

// 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;
Blackbaud-SandhyaRajasabeson marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* 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}.`);
}
Blackbaud-SandhyaRajasabeson marked this conversation as resolved.
Show resolved Hide resolved

await select.selectOptions(optionIndex);
}

/**
Expand Down
Loading