@@ -523,12 +523,10 @@ const LocationProbe: FC = () => {
) ;
} ;
function inputDate ( label : string , value : string ) {
const field = screen . getByLabelText ( label ) ;
fireEvent . focus ( field ) ;
fireEvent . input ( field , { target : { value } } ) ;
fireEvent . blur ( field ) ;
return field ;
function selectPeriod() {
fireEvent . click ( screen . getByLabelText ( "Период" ) ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : /^2 августа 2026$/i } ) ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : /^27 августа 2026$/i } ) ) ;
}
function respondWithRequestedPeriod ( requests : string [ ] ) {
@@ -557,9 +555,10 @@ describe("income period and snapshot boundary", () => {
const requests : string [ ] = [ ] ;
respondWithRequestedPeriod ( requests ) ;
renderPage ( ) ;
expect ( await screen . findByLabelText ( "С " ) ) . toHaveValue ( "01.08.2026" ) ;
expect ( screen . getByLabelText ( "По" ) ) . toHaveValue ( " 27.08.2026") ;
inputDate ( "С " , "02.08.2026" ) ;
expect ( await screen . findByLabelText ( "Период " ) ) . toHaveTextContent (
"01.08.2026 – 27.08.2026",
) ;
selectPeriod ( ) ;
expect ( requests ) . toHaveLength ( 1 ) ;
expect (
screen . queryByText ( "2026-08-01 — 2026-08-27" ) ,
@@ -573,66 +572,37 @@ describe("income period and snapshot boundary", () => {
. closest ( "form" ) as HTMLFormElement ,
) ;
await waitFor ( ( ) = > expect ( requests ) . toHaveLength ( 2 ) ) ;
expect ( await screen . findByLabelText ( "С " ) ) . toHaveValue ( "02.08.2026" ) ;
expect ( await screen . findByLabelText ( "Период " ) ) . toHaveTextContent (
"02.08.2026 – 27.08.2026" ,
) ;
expect ( screen . getByTestId ( "location" ) ) . toHaveTextContent (
"from=2026-08-02&to=2026-08-27" ,
) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Back" } ) ) ;
await waitFor ( ( ) = >
expect ( screen . getByLabelText ( "С " ) ) . toHaveValue ( "01.08.2026" ) ,
expect ( screen . getByLabelText ( "Период " ) ) . toHaveTextContent (
"01.08.2026 – 27.08.2026" ,
) ,
) ;
} ) ;
it . each ( [
[ "С " , "" , "Введите существующую дату" ] ,
[ "С " , "31.02.2026" , "Введите существующую дату" ] ,
[ "По" , "29.02.2026" , "Введите существующую дату" ] ,
[ "По" , "2026-08-02" , "Введите существующую дату" ] ,
[ "С " , "01.01.2099" , "Дата не может быть позже" ] ,
[ "По" , "01.01.2099" , "Дата не может быть позже" ] ,
[ "По" , "31.07.2026" , "Укажите корректный период" ] ,
] ) (
"rejects visible %s=%s without replacing data or URL" ,
async ( label , value , error ) = > {
const requests : string [ ] = [ ] ;
respondWithRequestedPeriod ( requests ) ;
renderPage ( ) ;
await screen . findByLabelText ( "С " ) ;
const field = inputDate ( label , value ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Применить" } ) ) ;
expect ( await screen . findByText ( new RegExp ( error ) ) ) . toBeInTheDocument ( ) ;
expect ( field ) . toHaveValue ( value ) ;
expect ( field ) . toHaveAttribute ( "aria-invalid" , "true" ) ;
await waitFor ( ( ) = > expect ( field ) . toHaveFocus ( ) ) ;
expect ( requests ) . toHaveLength ( 1 ) ;
expect ( screen . getByTestId ( "location" ) ) . toHaveTextContent (
"from=2026-08-01&to=2026-08-27" ,
) ;
expect (
screen . queryByText ( "2026-08-01 — 2026-08-27" ) ,
) . not . toBeInTheDocument ( ) ;
expect ( screen . getByRole ( "region" , { name : "Выплаты" } ) ) . toBeVisible ( ) ;
} ,
) ;
it ( "replaces invalid raw text with a calendar choice and closes the calendar with Escape" , async ( ) = > {
respondWithRequestedPeriod ( [ ] ) ;
it ( "rejects an incomplete range without replacing the URL and allows a single day" , async ( ) = > {
const requests : string [ ] = [ ] ;
respondWithRequestedPeriod ( requests ) ;
renderPage ( ) ;
const from = await screen . findByLabelText ( "С " ) ;
act ( ( ) = > from . focus ( ) ) ;
fireEvent . input ( from , { target : { value : "invalid" } } ) ;
// The selected month stays available even when the visible draft is invalid.
const day = await screen . findByRole ( "button" , {
name : /^2 августа 2026$/i ,
} ) ;
fireEvent . click ( day ) ;
expect ( from ) . toHaveValue ( "02.08.2026" ) ;
act ( ( ) = > from . focus ( ) ) ;
fireEvent . keyDown ( from , { key : "Escape " } ) ;
const period = await screen . findByLabelText ( "Период " ) ;
fireEvent . click ( period ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : /^2 августа 2026$/i } ) ) ;
fireEvent . keyDown ( period , { key : "Escape" } ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Применить" } ) ) ;
expect ( await screen . findByText ( /Введите существующую дату/ ) ) . toBeVisible ( ) ;
expect ( requests ) . toHaveLength ( 1 ) ;
if ( period . getAttribute ( "aria-expanded" ) !== "true" )
fireEvent . click ( period ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : /^2 августа 2026$/i } ) ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Применить " } ) ) ;
await waitFor ( ( ) = >
expect (
screen . queryByRole ( "button" , { name : /^2 августа 2026$/i } ) ,
) . not . toBeInTheDocument ( ) ,
expect ( requests . at ( - 1 ) ) . toBe ( "?from=2026-08-02&to=2026-08-02" ) ,
) ;
} ) ;
@@ -642,19 +612,23 @@ describe("income period and snapshot boundary", () => {
const requests : string [ ] = [ ] ;
respondWithRequestedPeriod ( requests ) ;
renderPage ( "" ) ;
expect ( await screen . findByLabelText ( "С " ) ) . toHaveValue ( "01.09.2026" ) ;
expect ( screen . getByLabelText ( "По" ) ) . toHaveValue ( "01.09.2026" ) ;
inputDate ( "С " , "wrong" ) ;
expect ( await screen . findByLabelText ( "Период " ) ) . toHaveTextContent (
"01.09.2026 – 01.09.2026" ,
) ;
fireEvent . click ( screen . getByLabelText ( "Период" ) ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : /^1 сентября 2026$/i } ) ) ;
fireEvent . keyDown ( screen . getByLabelText ( "Период" ) , { key : "Escape" } ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Применить" } ) ) ;
await screen . findByText ( /Введите существующую дату/ ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Сбросить" } ) ) ;
await waitFor ( ( ) = >
expect ( screen . getByLabelText ( "С " ) ) . toHaveValue ( "01.09.2026" ) ,
expect ( screen . getByLabelText ( "Период " ) ) . toHaveTextContent (
"01.09.2026 – 01.09.2026" ,
) ,
) ;
expect (
screen . queryByText ( /Введите существующую дату/ ) ,
) . not . toBeInTheDocument ( ) ;
expect ( screen . getByLabelText ( "По" ) ) . toHaveValue ( "01.09.2026" ) ;
expect ( screen . getByTestId ( "location" ) ) . toHaveTextContent (
"from=2026-09-01&to=2026-09-01" ,
) ;
@@ -664,8 +638,8 @@ describe("income period and snapshot boundary", () => {
it ( "keeps valid data and draft during refetch, warns on failure and retries" , async ( ) = > {
respondWithRequestedPeriod ( [ ] ) ;
const { queryClient } = renderPage ( ) ;
await screen . findByLabelText ( "С " ) ;
inputDate ( "С " , "02.08.2026" ) ;
await screen . findByLabelText ( "Период " ) ;
selectPeriod ( ) ;
let release ! : ( ) = > void ;
const pending = new Promise < void > ( ( resolve ) = > {
release = resolve ;
@@ -686,7 +660,9 @@ describe("income period and snapshot boundary", () => {
await screen . findByRole ( "status" , { name : "Обновляем пассивный доход" } ) ,
) . toBeInTheDocument ( ) ;
expect ( screen . getByRole ( "region" , { name : "Выплаты" } ) ) . toBeVisible ( ) ;
expect ( screen . getByLabelText ( "С " ) ) . toHaveValue ( "02.08.2026" ) ;
expect ( screen . getByLabelText ( "Период " ) ) . toHaveTextContent (
"02.08.2026 – 27.08.2026" ,
) ;
release ( ) ;
expect (
await screen . findByText ( /Показан последний загруженный результат/ ) ,
@@ -699,13 +675,15 @@ describe("income period and snapshot boundary", () => {
screen . queryByText ( /Показан последний загруженный результат/ ) ,
) . not . toBeInTheDocument ( ) ,
) ;
expect ( screen . getByLabelText ( "С " ) ) . toHaveValue ( "02.08.2026" ) ;
expect ( screen . getByLabelText ( "Период " ) ) . toHaveTextContent (
"02.08.2026 – 27.08.2026" ,
) ;
} ) ;
it ( "shows busy skeleton for a new uncached period without relabeling the previous result" , async ( ) = > {
respondWithRequestedPeriod ( [ ] ) ;
renderPage ( ) ;
await screen . findByLabelText ( "С " ) ;
await screen . findByLabelText ( "Период " ) ;
let release ! : ( ) = > void ;
const pending = new Promise < void > ( ( resolve ) = > {
release = resolve ;
@@ -722,7 +700,7 @@ describe("income period and snapshot boundary", () => {
} ,
) ,
) ;
inputDate ( "С " , "02.08.2026" ) ;
selectPeriod ( ) ;
fireEvent . click ( screen . getByRole ( "button" , { name : "Применить" } ) ) ;
expect (
await screen . findByRole ( "status" , { name : "Загрузка" } ) ,
@@ -734,7 +712,9 @@ describe("income period and snapshot boundary", () => {
screen . queryByText ( "2026-08-02 — 2026-08-27" ) ,
) . not . toBeInTheDocument ( ) ;
release ( ) ;
expect ( await screen . findByLabelText ( "С " ) ) . toHaveValue ( "02.08.2026" ) ;
expect ( await screen . findByLabelText ( "Период " ) ) . toHaveTextContent (
"02.08.2026 – 27.08.2026" ,
) ;
} ) ;
it ( "shows one flat payment card per entry in server order without currency or instrument groups" , ( ) = > {