@@ -3732,6 +3732,218 @@ for (const storage of ["account", "device"]) {
37323732 ) ;
37333733}
37343734
3735+ /// Names every report the page asks the browser to save, at the moment it
3736+ /// asks, so a test can say exactly which files one click produced rather than
3737+ /// waiting for download events that may still be on their way.
3738+ const recordDownloadNames = ( page ) =>
3739+ page . addInitScript ( ( ) => {
3740+ window . downloadNames = [ ] ;
3741+ const click = HTMLAnchorElement . prototype . click ;
3742+ HTMLAnchorElement . prototype . click = function ( ) {
3743+ if ( this . download ) window . downloadNames . push ( this . download ) ;
3744+ return click . call ( this ) ;
3745+ } ;
3746+ } ) ;
3747+ const takeDownloadNames = ( page ) =>
3748+ page . evaluate ( ( ) => window . downloadNames . splice ( 0 ) . sort ( ) ) ;
3749+
3750+ for ( const storage of [ "account" , "device" ] ) {
3751+ lobbyTest (
3752+ `saved ${ storage } reports download the ticked ones as their own markdown` ,
3753+ async ( page ) => {
3754+ const reportsSaved = [
3755+ { decision : "HIRE" , codingScore : 81 } ,
3756+ { decision : "NO_HIRE" , codingScore : 42 } ,
3757+ { incomplete : true , decision : "HIRE" } ,
3758+ ] ;
3759+ const entries = reportsSaved . map ( ( report , index ) => ( {
3760+ problemId : EASY [ 0 ] ,
3761+ problemTitle : "Saved report" ,
3762+ date : `2026-01-01T${ 17 + index } :30:00Z` ,
3763+ language : "python" ,
3764+ report : { ...report , summary : `Stored summary ${ index } ` } ,
3765+ } ) ) ;
3766+ if ( storage === "account" ) {
3767+ reports = entries . map ( ( payload ) => ( { payload } ) ) ;
3768+ } else {
3769+ session = { signedIn : false } ;
3770+ await page . addInitScript ( ( entries ) => {
3771+ localStorage . setItem ( "codetrial_history" , JSON . stringify ( entries ) ) ;
3772+ } , entries ) ;
3773+ }
3774+ await recordDownloadNames ( page ) ;
3775+ await lobby ( page ) ;
3776+ const history = page . locator ( "#attempt-history" ) ;
3777+ const boxes = history . getByRole ( "checkbox" ) ;
3778+ const toggle = page . locator ( "#attempt-select-all" ) ;
3779+ const downloadSelected = page . locator ( "#attempt-download-selected" ) ;
3780+ const note = page . locator ( "#attempt-download-note" ) ;
3781+ const when = ( index ) => `Jan 2, 2026, ${ index + 1 } :30 AM` ;
3782+ const box = ( index ) =>
3783+ history . getByRole ( "checkbox" , { name : `${ when ( index ) } · ` } ) ;
3784+ const filename = ( index ) =>
3785+ `interview-report-${ EASY [ 0 ] } -2026-01-02-0${ index + 1 } 3000.md` ;
3786+ const text = async ( download ) => {
3787+ const chunks = [ ] ;
3788+ for await ( const chunk of await download . createReadStream ( ) )
3789+ chunks . push ( chunk ) ;
3790+ return Buffer . concat ( chunks ) . toString ( "utf8" ) ;
3791+ } ;
3792+
3793+ assert . equal ( await boxes . count ( ) , reportsSaved . length ) ;
3794+ for ( const box of await boxes . all ( ) ) assert . ok ( await box . isChecked ( ) ) ;
3795+ assert . equal ( await toggle . textContent ( ) , "Deselect all" ) ;
3796+ assert . equal (
3797+ await downloadSelected . textContent ( ) ,
3798+ "Download selected (3)" ,
3799+ ) ;
3800+
3801+ // The description is the checkbox's label, so clicking the text toggles.
3802+ await history . locator ( "label" , { hasText : when ( 1 ) } ) . click ( ) ;
3803+ assert . equal ( await box ( 1 ) . isChecked ( ) , false ) ;
3804+ assert . equal ( await toggle . textContent ( ) , "Select all" ) ;
3805+ assert . equal (
3806+ await downloadSelected . textContent ( ) ,
3807+ "Download selected (2)" ,
3808+ ) ;
3809+
3810+ const batch = new Map ( ) ;
3811+ let onDownload ;
3812+ let timer ;
3813+ const arrived = new Promise ( ( resolve , reject ) => {
3814+ onDownload = ( download ) => {
3815+ batch . set ( download . suggestedFilename ( ) , download ) ;
3816+ if ( batch . size === 2 ) resolve ( ) ;
3817+ } ;
3818+ // node:test has no default timeout, so a download that never starts
3819+ // fails here with what did arrive instead of hanging the suite.
3820+ timer = setTimeout ( ( ) => {
3821+ const names = [ ...batch . keys ( ) ] . join ( ", " ) || "none" ;
3822+ reject ( new Error ( `only these downloads arrived: ${ names } ` ) ) ;
3823+ } , 10_000 ) ;
3824+ } ) ;
3825+ page . on ( "download" , onDownload ) ;
3826+ try {
3827+ await downloadSelected . click ( ) ;
3828+ assert . deepEqual ( await takeDownloadNames ( page ) , [
3829+ filename ( 0 ) ,
3830+ filename ( 2 ) ,
3831+ ] ) ;
3832+ assert . equal (
3833+ await note . textContent ( ) ,
3834+ "Your browser may ask to allow multiple downloads from this page. If only the first file arrived, allow automatic downloads for this site in the browser's site settings and try again." ,
3835+ ) ;
3836+ await arrived ;
3837+ } finally {
3838+ clearTimeout ( timer ) ;
3839+ page . off ( "download" , onDownload ) ;
3840+ }
3841+
3842+ // The batch reuses the row's own download, so each file it writes is the
3843+ // one that row's button writes, an incomplete report included.
3844+ for ( const index of [ 0 , 2 ] ) {
3845+ const downloading = page . waitForEvent ( "download" ) ;
3846+ await history
3847+ . getByRole ( "button" , {
3848+ name : `Download report (.md) for Saved report, ${ when ( index ) } ` ,
3849+ exact : true ,
3850+ } )
3851+ . click ( ) ;
3852+ const single = await downloading ;
3853+ assert . equal ( single . suggestedFilename ( ) , filename ( index ) ) ;
3854+ const markdown = await text ( single ) ;
3855+ assert . ok ( markdown . includes ( `Stored summary ${ index } ` ) ) ;
3856+ assert . equal ( await text ( batch . get ( filename ( index ) ) ) , markdown ) ;
3857+ }
3858+ await takeDownloadNames ( page ) ;
3859+
3860+ await toggle . click ( ) ;
3861+ for ( const box of await boxes . all ( ) ) assert . ok ( await box . isChecked ( ) ) ;
3862+ assert . equal ( await toggle . textContent ( ) , "Deselect all" ) ;
3863+ assert . equal (
3864+ await downloadSelected . textContent ( ) ,
3865+ "Download selected (3)" ,
3866+ ) ;
3867+
3868+ await toggle . click ( ) ;
3869+ for ( const box of await boxes . all ( ) )
3870+ assert . equal ( await box . isChecked ( ) , false ) ;
3871+ assert . equal ( await toggle . textContent ( ) , "Select all" ) ;
3872+ assert . equal (
3873+ await downloadSelected . textContent ( ) ,
3874+ "Download selected (0)" ,
3875+ ) ;
3876+ assert . equal ( await downloadSelected . isDisabled ( ) , true ) ;
3877+ } ,
3878+ { timezoneId : "Asia/Taipei" , locale : "en-US" , acceptDownloads : true } ,
3879+ ) ;
3880+ }
3881+
3882+ lobbyTest (
3883+ "a filtered attempt list keeps its ticks and downloads only what it shows" ,
3884+ async ( page ) => {
3885+ const attempt = ( id , language , day ) => ( {
3886+ id,
3887+ problemId : EASY [ 0 ] ,
3888+ payload : {
3889+ id,
3890+ problemId : EASY [ 0 ] ,
3891+ problemTitle : `Attempt ${ id } ` ,
3892+ language,
3893+ date : `2026-01-0${ day } T00:00:00Z` ,
3894+ report : { decision : "HIRE" } ,
3895+ } ,
3896+ } ) ;
3897+ reports = [
3898+ attempt ( "a" , "python" , 1 ) ,
3899+ attempt ( "b" , "cpp" , 2 ) ,
3900+ attempt ( "c" , "python" , 3 ) ,
3901+ ] ;
3902+ await recordDownloadNames ( page ) ;
3903+ await lobby ( page ) ;
3904+ const box = ( id ) =>
3905+ page . getByRole ( "checkbox" , { name : ` · Attempt ${ id } · ` } ) ;
3906+ const toggle = page . locator ( "#attempt-select-all" ) ;
3907+ const downloadSelected = page . locator ( "#attempt-download-selected" ) ;
3908+ const note = page . locator ( "#attempt-download-note" ) ;
3909+ const filename = ( day ) =>
3910+ `interview-report-${ EASY [ 0 ] } -2026-01-0${ day } -080000.md` ;
3911+
3912+ await box ( "a" ) . uncheck ( ) ;
3913+ await page . selectOption ( "#progress-language" , "python" ) ;
3914+ assert . equal ( await box ( "a" ) . isChecked ( ) , false ) ;
3915+ assert . equal ( await box ( "c" ) . isChecked ( ) , true ) ;
3916+ assert . equal ( await toggle . textContent ( ) , "Select all" ) ;
3917+ assert . equal ( await downloadSelected . textContent ( ) , "Download selected (1)" ) ;
3918+ await downloadSelected . click ( ) ;
3919+ assert . deepEqual ( await takeDownloadNames ( page ) , [ filename ( 3 ) ] ) ;
3920+ // One file is one download, which no browser asks about.
3921+ assert . equal ( await note . textContent ( ) , "" ) ;
3922+
3923+ await page . selectOption ( "#progress-language" , "cpp" ) ;
3924+ assert . equal ( await box ( "b" ) . isChecked ( ) , true ) ;
3925+ assert . equal ( await toggle . textContent ( ) , "Deselect all" ) ;
3926+ await downloadSelected . click ( ) ;
3927+ assert . deepEqual ( await takeDownloadNames ( page ) , [ filename ( 2 ) ] ) ;
3928+ await toggle . click ( ) ;
3929+ assert . equal ( await box ( "b" ) . isChecked ( ) , false ) ;
3930+ assert . equal ( await downloadSelected . isDisabled ( ) , true ) ;
3931+
3932+ await page . selectOption ( "#progress-language" , "all" ) ;
3933+ assert . equal ( await box ( "a" ) . isChecked ( ) , false ) ;
3934+ assert . equal ( await box ( "b" ) . isChecked ( ) , false ) ;
3935+ assert . equal ( await box ( "c" ) . isChecked ( ) , true ) ;
3936+ assert . equal ( await toggle . textContent ( ) , "Select all" ) ;
3937+ assert . equal ( await downloadSelected . textContent ( ) , "Download selected (1)" ) ;
3938+ // Some ticked is not all ticked, so the toggle ticks the rest.
3939+ await toggle . click ( ) ;
3940+ for ( const id of [ "a" , "b" , "c" ] )
3941+ assert . equal ( await box ( id ) . isChecked ( ) , true ) ;
3942+ assert . equal ( await downloadSelected . textContent ( ) , "Download selected (3)" ) ;
3943+ } ,
3944+ { timezoneId : "Asia/Taipei" , locale : "en-US" } ,
3945+ ) ;
3946+
37353947lobbyTest (
37363948 "try again selects a problem without escaping an active title search" ,
37373949 async ( page ) => {
0 commit comments