feat(challenge24): create challenge 24

This commit is contained in:
thomas
2023-06-12 21:52:41 +02:00
parent 58a6632552
commit f1bd68d78e
7 changed files with 90 additions and 18 deletions

View File

@@ -0,0 +1,55 @@
<h1>Create a component harness</h1>
> Author: Thomas Laforge
### Information
The goal of this challenge is to create a test harness for `slider.component.ts`. The harness file, `slider.harness.ts`, has already been created.
The following API needs to be implemented:
```ts
async clickPlus(): Promise<void> ;
async clickMinus(): Promise<void>;
async getValue(): Promise<number> ;
async getMinValue(): Promise<number>;
async disabled(): Promise<boolean>;
async setValue(value: number): Promise<void>;
```
Additionally, you should create a `HarnessPredicate` with the default predicate and the `minValue` property.
```ts
static with<T extends MySliderHarness>(
this: ComponentHarnessConstructor<T>,
options: SliderHarnessFilters = {}
): HarnessPredicate<T>;
```
Lastly, you will need to create the test suite for `app.component`. Some default tests have already been written, but feel free to add as many tests as you want and create as many harness methods as you need.
> Angular Material documentation can be found [here](https://material.angular.io/cdk/test-harnesses/overview)
Good luck !!! 💪
### Submitting your work
1. Fork the project
2. clone it
3. npm install
4. `npx nx serve create-harness`
5. _...work on it_
6. Commit your work
7. Submit a PR with a title beginning with **Answer:24** that I will review and other dev can review.
<a href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A24+label%3Aanswer"><img src="https://img.shields.io/badge/-Solutions-green" alt="create-harness"/></a>
<a href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A24+label%3A"answer+author"'><img src="https://img.shields.io/badge/-Author solution-important" alt="create-harness solution author"/></a>
<!-- <a href="{Blog post url}" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/-Blog post explanation-blue" alt="create-harness blog article"/></a> -->
_You can ask any question on_ <a href="https://twitter.com/laforge_toma" target="_blank" rel="noopener noreferrer"><img src="./../../logo/twitter.svg" height=20px alt="twitter"/></a>

View File

@@ -0,0 +1,15 @@
import { render } from '@testing-library/angular';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
test('select first slider and value must be 16 after clicking twice on plus button', async () => {
await render(AppComponent);
});
test('select first slider and click 1 time on plus button and twice on minus button, slider must be 10 again', async () => {
await render(AppComponent);
});
test('second slider is disabled, click 4 times on first slider and slider 2 must be enabled', async () => {
await render(AppComponent);
});
});

View File

@@ -13,14 +13,16 @@ import { SliderComponent } from './slider.component';
[maxValue]="30" [maxValue]="30"
(valueChange)="slider1Value.set($event)" /> (valueChange)="slider1Value.set($event)" />
<h2>Slider 2: {{ slider2Value() }}</h2> <h2>Slider 2: {{ slider2Value() }}</h2>
<p>Enabled only if Slider 1 > 20</p>
<app-slider <app-slider
[step]="10" [step]="10"
[maxValue]="1000" [maxValue]="1000"
[disabled]="slider1Value() < 20"
(valueChange)="slider2Value.set($event)" /> (valueChange)="slider2Value.set($event)" />
`, `,
styles: [''], styles: [''],
}) })
export class AppComponent { export class AppComponent {
slider1Value = signal(0); slider1Value = signal(10);
slider2Value = signal(0); slider2Value = signal(0);
} }

View File

@@ -1,5 +1,6 @@
import { ApplicationConfig } from '@angular/core'; import { ApplicationConfig } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [], providers: [provideAnimations()],
}; };

View File

@@ -1,8 +0,0 @@
import { render } from '@testing-library/angular';
import { SliderComponent } from './slider.component';
describe('SliderComponent', () => {
test('should have 1 slider, 3 checkboxes, 4 inputs, 2 buttons', async () => {
await render(SliderComponent);
});
});

View File

@@ -4,14 +4,15 @@ import { FormsModule } from '@angular/forms';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatSliderModule } from '@angular/material/slider'; import { MatSliderModule } from '@angular/material/slider';
import { skip } from 'rxjs';
@Component({ @Component({
selector: 'app-slider', selector: 'app-slider',
template: ` template: `
<mat-card class="flex"> <mat-card class="items-center">
<mat-card-content> <mat-card-content>
<div class="flex gap-10 items-center"> <div class="flex gap-10 items-center">
<button mat-mini-fab (click)="back()"> <button id="minusButton" mat-mini-fab (click)="back()">
<mat-icon>arrow_back_ios</mat-icon> <mat-icon>arrow_back_ios</mat-icon>
</button> </button>
{{ minValue }} {{ minValue }}
@@ -19,11 +20,15 @@ import { MatSliderModule } from '@angular/material/slider';
class="m-4" class="m-4"
[max]="maxValue" [max]="maxValue"
[min]="minValue" [min]="minValue"
[disabled]="disabled"
[step]="step"> [step]="step">
<input matSliderThumb [value]="value()" /> <input
matSliderThumb
[value]="value()"
(valueChange)="value.set($event)" />
</mat-slider> </mat-slider>
{{ maxValue }} {{ maxValue }}
<button mat-mini-fab (click)="forward()"> <button id="plusButton" mat-mini-fab (click)="forward()">
<mat-icon>arrow_forward_ios</mat-icon> <mat-icon>arrow_forward_ios</mat-icon>
</button> </button>
</div> </div>
@@ -37,21 +42,23 @@ import { MatSliderModule } from '@angular/material/slider';
width: 100%; width: 100%;
} }
.mat-mdc-card + .mat-mdc-card { .mat-mdc-card {
margin-top: 8px; margin-top: 8px;
flex-direction: row;
} }
`, `,
], ],
standalone: true, standalone: true,
imports: [MatCardModule, FormsModule, MatSliderModule, MatIconModule], imports: [MatCardModule, MatSliderModule, MatIconModule, FormsModule],
}) })
export class SliderComponent implements OnInit { export class SliderComponent implements OnInit {
@Input() step = 1; @Input() step = 1;
@Input() minValue = 0; @Input() minValue = 0;
@Input() maxValue = 100; @Input() maxValue = 100;
@Input() disabled = false;
value = signal(0); value = signal(0);
@Output() valueChange = toObservable(this.value); @Output() valueChange = toObservable(this.value).pipe(skip(1));
ngOnInit(): void { ngOnInit(): void {
this.value.set(this.minValue); this.value.set(this.minValue);

View File

@@ -1,5 +1,5 @@
import { ComponentHarness } from '@angular/cdk/testing'; import { ComponentHarness } from '@angular/cdk/testing';
class MySliderHarness extends ComponentHarness { export class MySliderHarness extends ComponentHarness {
static hostSelector = 'app-slider'; static hostSelector = 'app-slider';
} }