1212 */
1313
1414import { expect , Page } from '@playwright/test' ;
15+ import * as fs from 'fs' ;
16+ import * as path from 'path' ;
1517import { VIEW_ONLY_RULE } from '../../constant/permission' ;
1618import { KnowledgeCenterClass } from '../../support/entity/KnowledgeCenterClass' ;
1719import { ClassificationClass } from '../../support/tag/ClassificationClass' ;
@@ -841,6 +843,27 @@ test.describe('Context Center', () => {
841843 // ─── Documents Page ───────────────────────────────────────────────────────────
842844
843845 test . describe ( 'Documents Page' , ( ) => {
846+ const uploadFilePath = path . join (
847+ __dirname ,
848+ '..' ,
849+ 'output' ,
850+ 'context-center-upload.txt'
851+ ) ;
852+
853+ test . beforeAll ( ( ) => {
854+ const dir = path . dirname ( uploadFilePath ) ;
855+ if ( ! fs . existsSync ( dir ) ) {
856+ fs . mkdirSync ( dir , { recursive : true } ) ;
857+ }
858+ fs . writeFileSync ( uploadFilePath , 'context center upload test file' ) ;
859+ } ) ;
860+
861+ test . afterAll ( ( ) => {
862+ if ( fs . existsSync ( uploadFilePath ) ) {
863+ fs . unlinkSync ( uploadFilePath ) ;
864+ }
865+ } ) ;
866+
844867 test ( 'shows header with Upload File button' , async ( { page } ) => {
845868 await navigateToDocuments ( page ) ;
846869
@@ -894,15 +917,75 @@ test.describe('Context Center', () => {
894917 const modal = page . getByRole ( 'dialog' , { name : / u p l o a d d o c u m e n t s / i } ) ;
895918 await expect ( modal ) . toBeVisible ( ) ;
896919
897- // Set file directly on the hidden input
898- await modal . locator ( 'input[type="file"]' ) . setInputFiles ( {
899- name : 'test-upload.txt' ,
900- mimeType : 'text/plain' ,
901- buffer : Buffer . from ( 'playwright test file content' ) ,
902- } ) ;
920+ // Set file on the input via testId; wait for attached (not visible)
921+ const fileInput = page . getByTestId ( 'file-upload-input' ) ;
922+ console . log ( '[upload-test] resolved file path:' , uploadFilePath ) ;
923+
924+ await fileInput . waitFor ( { state : 'attached' } ) ;
925+ console . log ( '[upload-test] file input is attached to DOM' ) ;
926+
927+ // Snapshot the input's attributes before we touch it
928+ const inputAttrs = await fileInput . evaluate ( ( el : HTMLInputElement ) => ( {
929+ accept : el . accept ,
930+ disabled : el . disabled ,
931+ isConnected : el . isConnected ,
932+ multiple : el . multiple ,
933+ parentTag : el . parentElement ?. tagName ,
934+ type : el . type ,
935+ } ) ) ;
936+ console . log (
937+ '[upload-test] input attrs before setInputFiles:' ,
938+ JSON . stringify ( inputAttrs )
939+ ) ;
940+
941+ // Bridge: browser calls this Node function synchronously from the change
942+ // handler, so the log is guaranteed to arrive before setInputFiles resolves.
943+ // exposeFunction throws if already registered (e.g. test retry), so we guard.
944+ const bridgeFn = '__uploadTestChangeEvent' ;
945+ if ( ! ( page as unknown as Record < string , unknown > ) [ bridgeFn ] ) {
946+ await page . exposeFunction (
947+ bridgeFn ,
948+ ( info : { filesLength : number ; name : string ; size : number } ) => {
949+ console . log (
950+ '[upload-test][browser→node] change event fired —' ,
951+ 'files.length:' ,
952+ info . filesLength ,
953+ '| name:' ,
954+ info . name ,
955+ '| size:' ,
956+ info . size
957+ ) ;
958+ }
959+ ) ;
960+ }
961+
962+ // Register the change listener *then* call setInputFiles in one evaluate
963+ // so there is no round-trip gap between the two.
964+ await fileInput . evaluate ( ( el : HTMLInputElement , fn : string ) => {
965+ el . addEventListener (
966+ 'change' ,
967+ ( e ) => {
968+ const t = e . target as HTMLInputElement ;
969+ ( window as unknown as Record < string , ( arg : unknown ) => void > ) [ fn ] ( {
970+ filesLength : t . files ?. length ?? - 1 ,
971+ name : t . files ?. [ 0 ] ?. name ?? '(none)' ,
972+ size : t . files ?. [ 0 ] ?. size ?? - 1 ,
973+ } ) ;
974+ } ,
975+ { once : true }
976+ ) ;
977+ } , bridgeFn ) ;
978+
979+ await fileInput . setInputFiles ( uploadFilePath ) ;
903980
904981 // File appears in staged list
905- await expect ( modal . getByText ( 'test-upload.txt' ) . first ( ) ) . toBeVisible ( ) ;
982+ console . log (
983+ '[upload-test] waiting for filename to appear in staged list'
984+ ) ;
985+ await expect (
986+ modal . getByText ( 'context-center-upload.txt' ) . first ( )
987+ ) . toBeVisible ( ) ;
988+ console . log ( '[upload-test] filename visible in staged list' ) ;
906989
907990 // Attach the file
908991 const uploadResPromise = page . waitForResponse (
@@ -916,7 +999,7 @@ test.describe('Context Center', () => {
916999 await expect ( modal ) . not . toBeVisible ( ) ;
9171000
9181001 // File appears in document list
919- const docRow = page . getByText ( 'test -upload.txt' ) ;
1002+ const docRow = page . getByText ( 'context-center -upload.txt' ) ;
9201003 await expect ( docRow . first ( ) ) . toBeVisible ( ) ;
9211004 } ) ;
9221005
@@ -1018,7 +1101,9 @@ test.describe('Context Center', () => {
10181101
10191102 // Create a >5 MB in-memory buffer
10201103 const bigBuffer = Buffer . alloc ( 6 * 1024 * 1024 , 'x' ) ;
1021- await modal . locator ( 'input[type="file"]' ) . setInputFiles ( {
1104+ const oversizedInput = page . getByTestId ( 'file-upload-input' ) ;
1105+ await oversizedInput . waitFor ( { state : 'attached' } ) ;
1106+ await oversizedInput . setInputFiles ( {
10221107 name : 'too-large.bin' ,
10231108 mimeType : 'application/octet-stream' ,
10241109 buffer : bigBuffer ,
0 commit comments