-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(testing): add a slider element (#2053)
## Proposed change Add a slider element ## Related issues - 🚀 Feature #2045
- Loading branch information
Showing
14 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './autocomplete-material'; | ||
export * from './select-material'; | ||
export * from './slider-material'; |
19 changes: 19 additions & 0 deletions
19
packages/@o3r/testing/src/core/angular-materials/slider-material.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { O3rElement } from '../element'; | ||
import type { SliderElementProfile } from '../elements'; | ||
|
||
/** | ||
* Interface to describe the material Slider elements that are used inside a fixture. | ||
* As for ComponentFixtureProfile, this abstracts the testing framework that is used by choosing the right | ||
* implementation at runtime. | ||
*/ | ||
export interface MatSliderProfile extends SliderElementProfile {} | ||
|
||
/** | ||
* Mock for ElementProfile class. | ||
* This class is used for fixture compilation purpose. | ||
*/ | ||
export class MatSlider extends O3rElement implements MatSliderProfile { | ||
constructor(sourceElement: any) { | ||
super(sourceElement); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
packages/@o3r/testing/src/core/angular/angular-materials/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './autocomplete-material'; | ||
export * from './select-material'; | ||
export * from './slider-material'; |
21 changes: 21 additions & 0 deletions
21
packages/@o3r/testing/src/core/angular/angular-materials/slider-material.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { DebugElement } from '@angular/core'; | ||
import type { cssClasses } from '@material/slider'; | ||
import type { MatSliderProfile } from '../../angular-materials'; | ||
import { O3rElement } from '../element'; | ||
import { O3rSliderElement } from '../elements'; | ||
|
||
const TRACK_CLASS: typeof cssClasses.TRACK = 'mdc-slider__track'; | ||
const THUMB_CLASS: typeof cssClasses.THUMB = 'mdc-slider__thumb'; | ||
|
||
/** | ||
* Implementation dedicated to angular / TestBed. | ||
*/ | ||
export class MatSlider extends O3rSliderElement implements MatSliderProfile { | ||
constructor(sourceElement: DebugElement | O3rElement) { | ||
super( | ||
sourceElement instanceof O3rElement ? sourceElement.sourceElement : sourceElement, | ||
`.${TRACK_CLASS}`, | ||
`.${THUMB_CLASS}` | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './checkbox-element'; | ||
export * from './radio-element'; | ||
export * from './select-element'; | ||
export * from './slider-element'; |
83 changes: 83 additions & 0 deletions
83
packages/@o3r/testing/src/core/angular/elements/slider-element.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { DebugElement } from '@angular/core'; | ||
import { By } from '@angular/platform-browser'; | ||
import type { SliderElementProfile } from '../../elements'; | ||
import { O3rElement } from '../element'; | ||
|
||
/** | ||
* Implementation dedicated to angular / TestBed. | ||
*/ | ||
export class O3rSliderElement extends O3rElement implements SliderElementProfile { | ||
constructor( | ||
sourceElement: DebugElement, | ||
private readonly trackSelector?: string, | ||
private readonly thumbSelector?: string | ||
) { | ||
super(sourceElement); | ||
} | ||
|
||
private getInputElement() { | ||
try { | ||
const subElement = this.sourceElement.query(By.css('input[type="range"]')); | ||
return subElement || this.sourceElement; | ||
} catch { | ||
return this.sourceElement; | ||
} | ||
} | ||
|
||
private getTrackElement() { | ||
if (!this.trackSelector) { | ||
return this.sourceElement; | ||
} | ||
try { | ||
const subElement = this.sourceElement.query(By.css(this.trackSelector)); | ||
return subElement || this.sourceElement; | ||
} catch { | ||
return this.sourceElement; | ||
} | ||
} | ||
|
||
private getThumbElement() { | ||
if (!this.thumbSelector) { | ||
return this.sourceElement; | ||
} | ||
try { | ||
const subElement = this.sourceElement.query(By.css(this.thumbSelector)); | ||
return subElement || this.sourceElement; | ||
} catch { | ||
return this.sourceElement; | ||
} | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
* inspired from https://github.com/angular/components/blob/main/src/material/slider/slider.spec.ts#L1838 | ||
*/ | ||
public setValue(value: string): Promise<void> { | ||
const trackNativeElement = this.getTrackElement().nativeElement; | ||
const thumbNativeElement = this.getThumbElement().nativeElement; | ||
const inputNativeElement = this.getInputElement().nativeElement; | ||
const thumbBoundingBox: DOMRect = thumbNativeElement.getBoundingClientRect(); | ||
const startX = thumbBoundingBox.x + thumbBoundingBox.width / 2; | ||
const startY = thumbBoundingBox.y + thumbBoundingBox.height / 2; | ||
const max = +(inputNativeElement.max === '' ? '100' : inputNativeElement.max); | ||
const min = +(inputNativeElement.min === '' ? '0' : inputNativeElement.min); | ||
const sanitizeValue = Math.max(min, Math.min(+value, max)); | ||
const percent = (sanitizeValue - min) / (max - min); | ||
const { top, left, width, height } = trackNativeElement.getBoundingClientRect() as DOMRect; | ||
const endX = width * percent + left; | ||
const endY = top + height / 2; | ||
thumbNativeElement.dispatchEvent(new MouseEvent('mousedown', { clientX: startX, clientY: startY })); | ||
trackNativeElement.focus(); | ||
trackNativeElement.dispatchEvent(new MouseEvent('mousemove', { clientX: endX, clientY: endY })); | ||
inputNativeElement.value = `${sanitizeValue}`; | ||
inputNativeElement.dispatchEvent(new Event('input')); | ||
trackNativeElement.dispatchEvent(new MouseEvent('mouseup', { clientX: endX, clientY: endY })); | ||
inputNativeElement.dispatchEvent(new Event('change')); | ||
return Promise.resolve(); | ||
} | ||
|
||
/** @inheritdoc */ | ||
public getValue() { | ||
return (new O3rElement(this.getInputElement())).getValue(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './checkbox-element'; | ||
export * from './radio-element'; | ||
export * from './select-element'; | ||
export * from './slider-element'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ElementProfile, O3rElement } from '../element'; | ||
|
||
/** | ||
* Interface to describe the Slider elements that are used inside a fixture. | ||
* As for ComponentFixtureProfile, this abstracts the testing framework that is used by choosing the right | ||
* implementation at runtime. | ||
*/ | ||
export interface SliderElementProfile extends ElementProfile {} | ||
|
||
/** | ||
* Mock for ElementProfile class. | ||
* This class is used for fixture compilation purpose. | ||
*/ | ||
export class O3rSliderElement extends O3rElement implements SliderElementProfile { | ||
constructor(sourceElement: any, _trackSelector?: string, _thumbSelector?: string) { | ||
super(sourceElement); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
packages/@o3r/testing/src/core/playwright/angular-materials/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './autocomplete-material'; | ||
export * from './select-material'; | ||
export * from './slider-material'; |
16 changes: 16 additions & 0 deletions
16
packages/@o3r/testing/src/core/playwright/angular-materials/slider-material.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import type { cssClasses } from '@material/slider'; | ||
import type { MatSliderProfile } from '../../angular-materials'; | ||
import { O3rElement, type PlaywrightSourceElement } from '../element'; | ||
import { O3rSliderElement } from '../elements'; | ||
|
||
const TRACK_CLASS: typeof cssClasses.TRACK = 'mdc-slider__track'; | ||
const THUMB_CLASS: typeof cssClasses.THUMB = 'mdc-slider__thumb'; | ||
|
||
/** | ||
* Implementation dedicated to Playwright. | ||
*/ | ||
export class MatSlider extends O3rSliderElement implements MatSliderProfile { | ||
constructor(sourceElement: PlaywrightSourceElement | O3rElement) { | ||
super(sourceElement, `.${TRACK_CLASS}`, `.${THUMB_CLASS}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './select-element'; | ||
export * from './radio-element'; | ||
export * from './checkbox-element'; | ||
export * from './slider-element'; |
94 changes: 94 additions & 0 deletions
94
packages/@o3r/testing/src/core/playwright/elements/slider-element.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import type { SliderElementProfile } from '../../elements'; | ||
import { O3rElement, type PlaywrightSourceElement } from '../element'; | ||
|
||
/** | ||
* Implementation dedicated to Playwright. | ||
*/ | ||
export class O3rSliderElement extends O3rElement implements SliderElementProfile { | ||
constructor( | ||
sourceElement: PlaywrightSourceElement | O3rElement, | ||
private readonly trackSelector?: string, | ||
private readonly thumbSelector?: string | ||
) { | ||
super(sourceElement); | ||
} | ||
|
||
private async getInputElement() { | ||
try { | ||
const subElement = this.sourceElement.element.locator('input[type="range"]'); | ||
if (await subElement.count()) { | ||
return subElement.first(); | ||
} | ||
return this.sourceElement.element; | ||
} catch { | ||
return this.sourceElement.element; | ||
} | ||
} | ||
|
||
private async getTrackElement() { | ||
if (!this.trackSelector) { | ||
return this.sourceElement.element; | ||
} | ||
try { | ||
const subElement = this.sourceElement.element.locator(this.trackSelector); | ||
if (await subElement.count()) { | ||
return subElement.first(); | ||
} | ||
return this.sourceElement.element; | ||
} catch { | ||
return this.sourceElement.element; | ||
} | ||
} | ||
|
||
private async getThumbElement() { | ||
if (!this.thumbSelector) { | ||
return this.sourceElement.element; | ||
} | ||
try { | ||
const subElement = this.sourceElement.element.locator(this.thumbSelector); | ||
if (await subElement.count()) { | ||
return subElement.first(); | ||
} | ||
return this.sourceElement.element; | ||
} catch { | ||
return this.sourceElement.element; | ||
} | ||
} | ||
|
||
/** @inheritdoc */ | ||
public async setValue(value: string): Promise<void> { | ||
const trackElement = await this.getTrackElement(); | ||
const trackBoundingBox = await trackElement.boundingBox(); | ||
const thumbElement = await this.getThumbElement(); | ||
const inputElement = await this.getInputElement(); | ||
const thumbBoundingBox = await thumbElement.boundingBox(); | ||
if (!trackBoundingBox || !thumbBoundingBox) { | ||
return; | ||
} | ||
const startPosition = { | ||
x: thumbBoundingBox.x + thumbBoundingBox.width / 2, | ||
y: thumbBoundingBox.y + thumbBoundingBox.height / 2 | ||
}; | ||
await this.sourceElement.page.mouse.move(startPosition.x, startPosition.y); | ||
await this.sourceElement.page.mouse.down(); | ||
|
||
const maxAttribute = await inputElement.getAttribute('max'); | ||
const max = maxAttribute ? +maxAttribute : 100; | ||
const minAttribute = await inputElement.getAttribute('min'); | ||
const min = minAttribute ? +minAttribute : 0; | ||
const percent = (Math.max(min, Math.min(+value, max)) - min) / (max - min); | ||
await this.sourceElement.page.mouse.move( | ||
trackBoundingBox.x + Math.round(trackBoundingBox.width * percent), | ||
trackBoundingBox.y + trackBoundingBox.height / 2 | ||
); | ||
await this.sourceElement.page.mouse.up(); | ||
} | ||
|
||
/** @inheritdoc */ | ||
public async getValue() { | ||
return (new O3rElement({ | ||
element: await this.getInputElement(), | ||
page: this.sourceElement.page | ||
})).getValue(); | ||
} | ||
} |
Oops, something went wrong.