@@ -19,6 +19,10 @@ import {
1919// Each test registers a new user and creates test data, which needs more time
2020test . describe . configure ( { timeout : 60000 } ) ;
2121
22+ // Date picker button name patterns for different date formats
23+ const DATE_PICKER_BUTTON_PATTERN =
24+ / ^ P i c k a d a t e $ | ^ \d { 4 } - \d { 2 } - \d { 2 } $ | ^ \d { 2 } \/ \d { 2 } \/ \d { 4 } $ | ^ \d { 2 } \. \d { 2 } \. \d { 4 } $ / ;
25+
2226// ──────────────────────────────────────────────────
2327// Shared Report Lifecycle Tests
2428// ──────────────────────────────────────────────────
@@ -203,6 +207,128 @@ test('test that shared report with No Task filter shows entries without a task',
203207 await expect ( page . getByText ( 'Total' ) ) . toBeVisible ( ) ;
204208} ) ;
205209
210+ // ──────────────────────────────────────────────────
211+ // Report Date Picker Tests
212+ // ──────────────────────────────────────────────────
213+
214+ test ( 'test that creating a report with an expiration date works' , async ( { page } ) => {
215+ const projectName = 'DatePickerProj ' + Math . floor ( Math . random ( ) * 10000 ) ;
216+ const reportName = 'DatePickerReport ' + Math . floor ( Math . random ( ) * 10000 ) ;
217+
218+ await createProject ( page , projectName ) ;
219+ await createTimeEntryWithProject ( page , projectName , '1h' ) ;
220+
221+ await goToReporting ( page ) ;
222+ await expect ( page . getByTestId ( 'reporting_view' ) . getByText ( projectName ) ) . toBeVisible ( ) ;
223+
224+ // Open the save report modal
225+ await page . getByRole ( 'button' , { name : 'Save Report' } ) . click ( ) ;
226+ await page . getByLabel ( 'Name' ) . fill ( reportName ) ;
227+
228+ // The "Public" checkbox should be checked by default, showing the date picker
229+ const datePicker = page
230+ . getByRole ( 'dialog' )
231+ . getByRole ( 'button' , { name : DATE_PICKER_BUTTON_PATTERN } ) ;
232+ await expect ( datePicker ) . toBeVisible ( ) ;
233+ await datePicker . click ( ) ;
234+
235+ // Select a date in the next month
236+ const calendarGrid = page . getByRole ( 'grid' ) ;
237+ await expect ( calendarGrid ) . toBeVisible ( { timeout : 5000 } ) ;
238+ await page . getByRole ( 'button' , { name : / N e x t / i } ) . click ( ) ;
239+ await page . getByRole ( 'gridcell' ) . filter ( { hasText : / ^ 1 5 $ / } ) . first ( ) . click ( ) ;
240+
241+ // Wait for the calendar to close
242+ await expect ( calendarGrid ) . not . toBeVisible ( ) ;
243+
244+ // Create the report and verify it includes the public_until date
245+ const [ response ] = await Promise . all ( [
246+ page . waitForResponse (
247+ ( response ) =>
248+ response . url ( ) . includes ( '/reports' ) &&
249+ response . request ( ) . method ( ) === 'POST' &&
250+ response . status ( ) === 201
251+ ) ,
252+ page . getByRole ( 'dialog' ) . getByRole ( 'button' , { name : 'Create Report' } ) . click ( ) ,
253+ ] ) ;
254+ const responseBody = await response . json ( ) ;
255+ expect ( responseBody . data . public_until ) . toBeTruthy ( ) ;
256+ } ) ;
257+
258+ test ( 'test that editing a report to make it public with expiration date works' , async ( {
259+ page,
260+ } ) => {
261+ const projectName = 'EditDateProj ' + Math . floor ( Math . random ( ) * 10000 ) ;
262+ const reportName = 'EditDateReport ' + Math . floor ( Math . random ( ) * 10000 ) ;
263+
264+ await createProject ( page , projectName ) ;
265+ await createTimeEntryWithProject ( page , projectName , '1h' ) ;
266+
267+ await goToReporting ( page ) ;
268+ await expect ( page . getByTestId ( 'reporting_view' ) . getByText ( projectName ) ) . toBeVisible ( ) ;
269+
270+ // Open the save report modal and create a private report
271+ await page . getByRole ( 'button' , { name : 'Save Report' } ) . click ( ) ;
272+ await page . getByLabel ( 'Name' ) . fill ( reportName ) ;
273+
274+ // Uncheck "Public" to create a private report
275+ await page . getByLabel ( 'Public' ) . click ( ) ;
276+
277+ await Promise . all ( [
278+ page . waitForResponse (
279+ ( response ) =>
280+ response . url ( ) . includes ( '/reports' ) &&
281+ response . request ( ) . method ( ) === 'POST' &&
282+ response . status ( ) === 201
283+ ) ,
284+ page . getByRole ( 'dialog' ) . getByRole ( 'button' , { name : 'Create Report' } ) . click ( ) ,
285+ ] ) ;
286+
287+ // Go to shared reports and edit
288+ await goToReportingShared ( page ) ;
289+ await expect ( page . getByText ( reportName ) ) . toBeVisible ( ) ;
290+ await expect ( page . getByText ( 'Private' ) ) . toBeVisible ( ) ;
291+
292+ // Click more options and edit
293+ await page
294+ . getByRole ( 'button' , { name : new RegExp ( 'Actions for Project ' + reportName ) } )
295+ . click ( ) ;
296+ await page . getByRole ( 'menuitem' , { name : / ^ E d i t R e p o r t / } ) . click ( ) ;
297+
298+ // Check "Public" to make it public - this should show the date picker
299+ await page . getByLabel ( 'Public' ) . click ( ) ;
300+
301+ // The date picker should now be visible
302+ const datePicker = page
303+ . getByRole ( 'dialog' )
304+ . getByRole ( 'button' , { name : DATE_PICKER_BUTTON_PATTERN } ) ;
305+ await expect ( datePicker ) . toBeVisible ( ) ;
306+ await datePicker . click ( ) ;
307+
308+ // Select a date in the next month
309+ const calendarGrid = page . getByRole ( 'grid' ) ;
310+ await expect ( calendarGrid ) . toBeVisible ( { timeout : 5000 } ) ;
311+ await page . getByRole ( 'button' , { name : / N e x t / i } ) . click ( ) ;
312+ await page . getByRole ( 'gridcell' ) . filter ( { hasText : / ^ 2 0 $ / } ) . first ( ) . click ( ) ;
313+
314+ // Wait for the calendar to close
315+ await expect ( calendarGrid ) . not . toBeVisible ( ) ;
316+
317+ // Update the report and verify it includes the public_until date
318+ const [ response ] = await Promise . all ( [
319+ page . waitForResponse (
320+ ( response ) =>
321+ response . url ( ) . includes ( '/reports/' ) &&
322+ response . request ( ) . method ( ) === 'PUT' &&
323+ response . status ( ) === 200
324+ ) ,
325+ page . getByRole ( 'button' , { name : 'Update Report' } ) . click ( ) ,
326+ ] ) ;
327+ const responseBody = await response . json ( ) ;
328+ expect ( responseBody . data . public_until ) . toBeTruthy ( ) ;
329+ expect ( responseBody . data . is_public ) . toBe ( true ) ;
330+ } ) ;
331+
206332test ( 'test that shared report with No Client filter shows entries without a client' , async ( {
207333 page,
208334} ) => {
0 commit comments