import { ErrorArea , RustPanic , isCi } from '@prisma/sdk' ; import fs from 'fs' ; import mkdir from 'make-dir' ; import { stdin } from 'mock-stdin' ; import { dirname , join , resolve } from 'path' ; import stripAnsi from 'strip-ansi' ; import dedent from 'strip-indent' ; import prompt from 'prompts' ; import tempy from 'tempy' ; import { promisify } from 'util' ; import { Migrate } from '../Migrate' ; import { handlePanic } from '../utils/handlePanic' ; import CaptureStdout from './__helpers__/captureStdout' ; const keys = { up : '\x1B\x5B\x41' , down : '\x1B\x5B\x42' , enter : '\x0D' , space : '\x20' , } ; const sendKeystrokes = async ( io ) => { io . send ( keys . down ) ; io . send ( keys . enter ) ; await delay ( 10 ) ; } ; const delay = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ; const writeFile = promisify ( fs . writeFile ) ; const testRootDir = tempy . directory ( ) ; const oldProcessCwd = process . cwd ; async function writeFiles ( root , files ) { for ( const name in files ) { const filepath = join ( root , name ) ; await mkdir ( dirname ( filepath ) ) ; await writeFile ( filepath , dedent ( files [ name ] ) ) ; } return root ; } describe ( 'handlePanic' , ( ) => { const OLD_ENV = process . env ; beforeEach ( async ( ) => { jest . resetModules ( ) ; process . env = { ... OLD_ENV } ; process . cwd = ( ) => testRootDir ; await mkdir ( testRootDir ) ; } ) ; afterEach ( async ( ) => { process . cwd = oldProcessCwd ; } ) ; let io ; beforeAll ( ( ) => ( io = stdin ( ) ) ) ; afterAll ( ( ) => { process . env = OLD_ENV ; io . restore ( ) ; } ) ; const error = new RustPanic ( 'Some error message!' , '' , undefined , ErrorArea . LIFT_CLI , resolve ( join ( 'fixtures' , 'blog' , 'prisma' , 'schema.prisma' ) ) ) ; const packageJsonVersion = '0.0.0' ; const engineVersion = '734ab53bd8e2cadf18b8b71cb53bf2d2bed46517' ; const command = 'something-test' ; it . skip ( 'ask to submit the panic error in interactive mode' , async ( ) => { const oldConsoleLog = console . log ; const logs = [ ] ; console . log = ( ... args ) => { logs . push ( ... args ) ; } ; setTimeout ( ( ) => sendKeystrokes ( io ) . then ( ) , 5 ) ; try { await handlePanic ( error , packageJsonVersion , engineVersion , command ) ; } catch ( e ) { expect ( stripAnsi ( e . message ) ) . toMatchSnapshot ( ) ; } console . log = oldConsoleLog ; expect ( stripAnsi ( logs . join ( '\n' ) ) ) . toMatchSnapshot ( ) ; } ) ; it ( 'no interactive mode in CI' , async ( ) => { process . env . GITHUB_ACTIONS = 'maybe' ; try { await handlePanic ( error , packageJsonVersion , engineVersion , command ) ; } catch ( error ) { error . schemaPath = 'Some Schema Path' ; expect ( error ) . toMatchInlineSnapshot ( `Some error message!` ) ; expect ( JSON . stringify ( error ) ) . toMatchInlineSnapshot ( `{"rustStack":"","area":"LIFT_CLI","schemaPath":"Some Schema Path"}` ) ; } } ) ; it ( 'test interactive engine panic' , async ( ) => { process . env . FORCE_PANIC_MIGRATION_ENGINE = '1' ; const captureStdout = new CaptureStdout ( ) ; const files = { 'schema.prisma' : `
        datasource my_db {
          provider = "sqlite"
          url = "file:./db/db_file.db"
          default = true
        }

        model User {
          id Int @id
        }
      ` , 'db/.keep' : `` , } ; const schemaPath = join ( testRootDir , Object . keys ( files ) [ 0 ] ) ; await writeFiles ( testRootDir , files ) ; captureStdout . startCapture ( ) ; let error ; try { const migrate = new Migrate ( schemaPath ) ; await migrate . createMigration ( { migrationsDirectoryPath : migrate . migrationsDirectoryPath , migrationName : 'setup' , draft : false , prismaSchema : migrate . getDatamodel ( ) , } ) ; } catch ( err ) { setTimeout ( ( ) => sendKeystrokes ( io ) . then ( ) , 5 ) ; setTimeout ( ( ) => sendKeystrokes ( io ) . then ( ) , 5 ) ; try { await handlePanic ( err , packageJsonVersion , engineVersion , command ) ; } catch ( err ) { error = err ; } } if ( isCi ( ) && Boolean ( ( prompt as any ) . _injected ?. length ) === false ) { expect ( error ) . toMatchInlineSnapshot ( `
        Error in migration engine.
        Reason: [/some/rust/path:0:0] This is the debugPanic artificial panic

        Please create an issue with your \`schema.prisma\` at
        https://github.com/prisma/prisma/issues/new

      ` ) ; } else { const output = captureStdout . getCapturedText ( ) ; expect ( stripAnsi ( output . join ( '\n' ) ) ) . toMatchInlineSnapshot ( `

                                  console.log    Oops, an unexpected error occured!    Error in migration engine.    Reason: [/some/rust/path:0:0] This is the debugPanic artificial panic        Please create an issue with your \`schema.prisma\` at     https://github.com/prisma/prisma/issues/new            Please help us improve Prisma by submitting an error report.    Error reports never contain personal or other sensitive information.    Learn more: https://pris.ly/d/telemetry      at panicDialog (src/utils/handlePanic.ts:25:11)

                                ? Submit error report › - Use arrow-keys. Return to submit.❯   Yes - Send error report once    No

                                ? Submit error report › - Use arrow-keys. Return to submit.    Yes❯   No - Don't send error report

                                ✔ Submit error report › No



                                ? Would you like to create a Github issue? › - Use arrow-keys. Return to submit.❯   Yes - Create a new GitHub issue    No

                                ? Would you like to create a Github issue? › - Use arrow-keys. Return to submit.    Yes❯   No - Don't create a new GitHub issue

                                ✔ Would you like to create a Github issue? › No


                        ` ) ; } captureStdout . stopCapture ( ) ; } ) ; it ( 'engine panic no interactive mode in CI' , async ( ) => { process . env . GITHUB_ACTIONS = 'maybe' ; process . env . FORCE_PANIC_MIGRATION_ENGINE = '1' ; const files = { 'schema.prisma' : `
        datasource my_db {
          provider = "sqlite"
          url = "file:./db/db_file.db"
          default = true
        }

        model User {
          id Int @id
        }
      ` , 'db/.keep' : `` , } ; const schemaPath = join ( testRootDir , Object . keys ( files ) [ 0 ] ) ; await writeFiles ( testRootDir , files ) ; try { const migrate = new Migrate ( schemaPath ) ; await migrate . createMigration ( { migrationsDirectoryPath : migrate . migrationsDirectoryPath , migrationName : 'setup' , draft : false , prismaSchema : migrate . getDatamodel ( ) , } ) ; } catch ( err ) { expect ( error ) . toMatchInlineSnapshot ( `Some error message!` ) ; expect ( JSON . stringify ( error ) ) . toMatchInlineSnapshot ( `{"rustStack":"","area":"LIFT_CLI","schemaPath":"Some Schema Path"}` ) ; } } ) ; } ) ;