|
5 | 5 | * LICENSE file in the root directory of this source tree. |
6 | 6 | */ |
7 | 7 |
|
8 | | -import React from 'react'; |
| 8 | +import React, { useState } from 'react'; |
9 | 9 | import Slider from '../Slider'; |
10 | 10 | import userEvent from '@testing-library/user-event'; |
11 | 11 | import { |
@@ -267,6 +267,153 @@ describe('Slider', () => { |
267 | 267 | expect(onChange).toHaveBeenLastCalledWith({ value: 999 }); |
268 | 268 | }); |
269 | 269 |
|
| 270 | + it('should keep controlled invalid state after dragging to another invalid value', async () => { |
| 271 | + const ControlledSlider = () => { |
| 272 | + const [value, setValue] = useState(20); |
| 273 | + |
| 274 | + return ( |
| 275 | + <Slider |
| 276 | + labelText="Slider" |
| 277 | + value={value} |
| 278 | + min={0} |
| 279 | + max={100} |
| 280 | + ariaLabelInput={inputAriaValue} |
| 281 | + invalid={value > 25} |
| 282 | + invalidText="Error message" |
| 283 | + onChange={({ value }) => setValue(value)} |
| 284 | + /> |
| 285 | + ); |
| 286 | + }; |
| 287 | + |
| 288 | + render(<ControlledSlider />); |
| 289 | + |
| 290 | + const inputElement = screen.getByLabelText(inputAriaValue); |
| 291 | + const slider = screen.getByRole('slider'); |
| 292 | + const sliderRoot = screen.getByRole('presentation'); |
| 293 | + |
| 294 | + jest |
| 295 | + .spyOn(sliderRoot, 'getBoundingClientRect') |
| 296 | + .mockImplementation(() => createDOMRect({ left: 0, width: 100 })); |
| 297 | + |
| 298 | + await userEvent.clear(inputElement); |
| 299 | + await userEvent.type(inputElement, '30'); |
| 300 | + |
| 301 | + expect(inputElement).toHaveAttribute('aria-invalid', 'true'); |
| 302 | + expect(screen.getByText('Error message')).toBeInTheDocument(); |
| 303 | + |
| 304 | + fireEvent.mouseDown(slider, { clientX: 35 }); |
| 305 | + fireEvent.mouseUp(document); |
| 306 | + |
| 307 | + await waitFor(() => { |
| 308 | + expect(slider).toHaveAttribute('aria-valuenow', '35'); |
| 309 | + }); |
| 310 | + |
| 311 | + expect(screen.getByLabelText(inputAriaValue)).toHaveAttribute( |
| 312 | + 'aria-invalid', |
| 313 | + 'true' |
| 314 | + ); |
| 315 | + expect(screen.getByText('Error message')).toBeInTheDocument(); |
| 316 | + }); |
| 317 | + |
| 318 | + it('should keep controlled invalid state after keyboard interaction changes to another invalid value', async () => { |
| 319 | + const ControlledSlider = () => { |
| 320 | + const [value, setValue] = useState(20); |
| 321 | + |
| 322 | + return ( |
| 323 | + <Slider |
| 324 | + labelText="Slider" |
| 325 | + value={value} |
| 326 | + min={0} |
| 327 | + max={100} |
| 328 | + ariaLabelInput={inputAriaValue} |
| 329 | + invalid={value > 25} |
| 330 | + invalidText="Error message" |
| 331 | + onChange={({ value }) => setValue(value)} |
| 332 | + /> |
| 333 | + ); |
| 334 | + }; |
| 335 | + |
| 336 | + render(<ControlledSlider />); |
| 337 | + |
| 338 | + const inputElement = screen.getByLabelText(inputAriaValue); |
| 339 | + const slider = screen.getByRole('slider'); |
| 340 | + |
| 341 | + await userEvent.clear(inputElement); |
| 342 | + await userEvent.type(inputElement, '30'); |
| 343 | + |
| 344 | + expect(inputElement).toHaveAttribute('aria-invalid', 'true'); |
| 345 | + expect(screen.getByText('Error message')).toBeInTheDocument(); |
| 346 | + |
| 347 | + await userEvent.click(slider); |
| 348 | + await userEvent.keyboard('{ArrowRight}'); |
| 349 | + |
| 350 | + await waitFor(() => { |
| 351 | + expect(slider).toHaveAttribute('aria-valuenow', '31'); |
| 352 | + }); |
| 353 | + |
| 354 | + expect(screen.getByLabelText(inputAriaValue)).toHaveAttribute( |
| 355 | + 'aria-invalid', |
| 356 | + 'true' |
| 357 | + ); |
| 358 | + expect(screen.getByText('Error message')).toBeInTheDocument(); |
| 359 | + }); |
| 360 | + |
| 361 | + it('should keep controlled invalid state for the upper handle after dragging to another invalid value', async () => { |
| 362 | + const ControlledRangeSlider = () => { |
| 363 | + const [value, setValue] = useState(20); |
| 364 | + const [valueUpper, setValueUpper] = useState(70); |
| 365 | + |
| 366 | + return ( |
| 367 | + <Slider |
| 368 | + labelText="Slider" |
| 369 | + value={value} |
| 370 | + unstable_valueUpper={valueUpper} |
| 371 | + min={0} |
| 372 | + max={100} |
| 373 | + ariaLabelInput={defaultAriaLabelInput} |
| 374 | + unstable_ariaLabelInputUpper={defaultAriaLabelInputUpper} |
| 375 | + invalid={valueUpper > 75} |
| 376 | + invalidText="Error message" |
| 377 | + onChange={({ value, valueUpper }) => { |
| 378 | + setValue(value); |
| 379 | + if (typeof valueUpper !== 'undefined') { |
| 380 | + setValueUpper(valueUpper); |
| 381 | + } |
| 382 | + }} |
| 383 | + /> |
| 384 | + ); |
| 385 | + }; |
| 386 | + |
| 387 | + render(<ControlledRangeSlider />); |
| 388 | + |
| 389 | + const upperInput = screen.getByLabelText(defaultAriaLabelInputUpper, { |
| 390 | + selector: 'input', |
| 391 | + }); |
| 392 | + const sliderRoot = screen.getByRole('presentation'); |
| 393 | + const [lowerThumb, upperThumb] = screen.getAllByRole('slider'); |
| 394 | + |
| 395 | + jest |
| 396 | + .spyOn(sliderRoot, 'getBoundingClientRect') |
| 397 | + .mockImplementation(() => createDOMRect({ left: 0, width: 100 })); |
| 398 | + |
| 399 | + await userEvent.clear(upperInput); |
| 400 | + await userEvent.type(upperInput, '80'); |
| 401 | + |
| 402 | + expect(upperInput).toHaveAttribute('aria-invalid', 'true'); |
| 403 | + expect(screen.getByText('Error message')).toBeInTheDocument(); |
| 404 | + |
| 405 | + fireEvent.mouseDown(upperThumb, { clientX: 84 }); |
| 406 | + fireEvent.mouseUp(document); |
| 407 | + |
| 408 | + await waitFor(() => { |
| 409 | + expect(upperThumb).toHaveAttribute('aria-valuenow', '84'); |
| 410 | + }); |
| 411 | + |
| 412 | + expect(lowerThumb).toHaveAttribute('aria-valuenow', '20'); |
| 413 | + expect(upperInput).toHaveAttribute('aria-invalid', 'true'); |
| 414 | + expect(screen.getByText('Error message')).toBeInTheDocument(); |
| 415 | + }); |
| 416 | + |
270 | 417 | it('sets correct state when typing a valid value in input field', async () => { |
271 | 418 | const { type } = userEvent; |
272 | 419 | renderSlider({ |
|
0 commit comments