import { expect } from 'chai' ; import * as fs from 'fs' ; import * as jestTestSupport from 'jest-editor-support' ; import { SinonStub , stub } from 'sinon' ; import * as vscode from 'vscode' ; import URI from 'vscode-uri' ; import { lwcTestIndexer } from '../../../../src/testSupport/testIndexer' ; import { TestFileInfo , TestInfoKind , TestResultStatus , TestType } from '../../../../src/testSupport/types' ; describe ( 'LWC Test Indexer' , ( ) => { let lwcTests ; let existingTestFileCount ; before ( async ( ) => { lwcTests = await vscode . workspace . findFiles ( new vscode . RelativePattern ( vscode . workspace . workspaceFolders ! [ 0 ] , '**/lwc/**/*.test.js' ) ) ; existingTestFileCount = lwcTests . length ; } ) ; describe ( 'Test Indexer File Watcher' , ( ) => { let onDidCreateEventEmitter ; let onDidChangeEventEmitter ; let onDidDeleteEventEmitter ; let readFileStub ; let mockFileSystemWatcher ; let createFileSystemWatcherStub ; let parseStub ; beforeEach ( async ( ) => { createFileSystemWatcherStub = stub ( vscode . workspace , 'createFileSystemWatcher' ) ; onDidCreateEventEmitter = new vscode . EventEmitter < vscode . Uri > ( ) ; onDidChangeEventEmitter = new vscode . EventEmitter < vscode . Uri > ( ) ; onDidDeleteEventEmitter = new vscode . EventEmitter < vscode . Uri > ( ) ; mockFileSystemWatcher = { onDidCreate : onDidCreateEventEmitter . event , onDidChange : onDidChangeEventEmitter . event , onDidDelete : onDidDeleteEventEmitter . event } ; createFileSystemWatcherStub . returns ( mockFileSystemWatcher as vscode . FileSystemWatcher ) ; const mockFile = `it('mockTestCase1', () => {})\nit('mockTestCase2', () => {})\n` ; readFileStub = stub ( fs , 'readFileSync' ) ; readFileStub . callsFake ( fileName => { return mockFile ; } ) ; await lwcTestIndexer . configureAndIndex ( ) ; lwcTestIndexer . resetIndex ( ) ; } ) ; afterEach ( ( ) => { onDidCreateEventEmitter . dispose ( ) ; onDidChangeEventEmitter . dispose ( ) ; onDidDeleteEventEmitter . dispose ( ) ; createFileSystemWatcherStub . restore ( ) ; readFileStub . restore ( ) ; } ) ; function assertTestCasesMatch ( actualTestFileInfo , expectedFilePath ) { const expectedTestCases = [ { testFsPath : expectedFilePath , testName : 'mockTestCase1' } , { testFsPath : expectedFilePath , testName : 'mockTestCase2' } ] ; expect ( actualTestFileInfo ! . testCasesInfo ! . map ( testCaseInfo => { const { testName , testUri } = testCaseInfo ; return { testFsPath : testUri . fsPath , testName } ; } ) ) . to . eql ( expectedTestCases ) ; } it ( 'should update index on test file create' , async ( ) => { let allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount ) ; const mockFilePath = /^win32/ . test ( process . platform ) ? 'C:\\Users\\tester\\mockNewFile.test.js' : '/Users/tester/mockNewFile.test.js' ; const mockFileUri = URI . file ( mockFilePath ) ; return new Promise ( resolve => { const handleDidUpdateTestIndex = lwcTestIndexer . onDidUpdateTestIndex ( async ( ) => { allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount + 1 ) ; const createdTestFileInfo = allTestFileInfo . find ( ( testFileInfo ) => { return testFileInfo . testUri . fsPath === mockFileUri . fsPath ; } ) ; expect ( createdTestFileInfo ! . kind ) . to . equal ( TestInfoKind . TEST_FILE ) ; expect ( createdTestFileInfo ! . testType ) . to . equal ( TestType . LWC ) ; expect ( createdTestFileInfo ! . testLocation ! . uri . fsPath ) . to . equal ( mockFileUri . fsPath ) ; expect ( createdTestFileInfo ! . testLocation ! . range . start . line ) . to . equal ( 0 ) ; expect ( createdTestFileInfo ! . testLocation ! . range . start . character ) . to . equal ( 0 ) ; expect ( createdTestFileInfo ! . testLocation ! . range . end . line ) . to . equal ( 0 ) ; expect ( createdTestFileInfo ! . testLocation ! . range . end . character ) . to . equal ( 0 ) ; assertTestCasesMatch ( createdTestFileInfo , mockFileUri . fsPath ) ; handleDidUpdateTestIndex . dispose ( ) ; resolve ( ) ; } ) ; onDidCreateEventEmitter . fire ( mockFileUri ) ; } ) ; } ) ; it ( 'should update index on test file change' , async ( ) => { const testFileUriToChange = lwcTests [ 0 ] ; let allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount ) ; return new Promise ( resolve => { const handleDidUpdateTestIndex = lwcTestIndexer . onDidUpdateTestIndex ( async ( ) => { allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; const changedTestFileInfo = allTestFileInfo . find ( ( testFileInfo ) => { return ( testFileInfo . testUri . fsPath === testFileUriToChange . fsPath ) ; } ) ; assertTestCasesMatch ( changedTestFileInfo , testFileUriToChange . fsPath ) ; handleDidUpdateTestIndex . dispose ( ) ; resolve ( ) ; } ) ; onDidChangeEventEmitter . fire ( testFileUriToChange ) ; } ) ; } ) ; it ( 'should update index on test file change when parsing has an error' , async ( ) => { readFileStub . callsFake ( fileName => { throw new Error ( ) ; } ) ; const testFileUriToChange = lwcTests [ 0 ] ; let allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount ) ; return new Promise ( resolve => { const handleDidUpdateTestIndex = lwcTestIndexer . onDidUpdateTestIndex ( async ( ) => { allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; const changedTestFileInfo = allTestFileInfo . find ( ( testFileInfo ) => { return ( testFileInfo . testUri . fsPath === testFileUriToChange . fsPath ) ; } ) ; expect ( changedTestFileInfo ! . testCasesInfo ) . to . eql ( [ ] ) ; handleDidUpdateTestIndex . dispose ( ) ; resolve ( ) ; } ) ; onDidChangeEventEmitter . fire ( testFileUriToChange ) ; } ) ; } ) ; it ( 'should update index on test file change and merge existing test results if possible' , async ( ) => { const testFileUriToChange = lwcTests [ 0 ] ; let allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount ) ; const testFileInfoToChange = allTestFileInfo . find ( ( testFileInfo ) => { return testFileInfo . testUri . fsPath === testFileUriToChange . fsPath ; } ) ; testFileInfoToChange ! . rawTestResults = [ { title : 'mockTestCase1' , ancestorTitles : [ ] , status : TestResultStatus . PASSED } , { title : 'mockTestCase2' , ancestorTitles : [ ] , status : TestResultStatus . FAILED } ] ; return new Promise ( resolve => { const handleDidUpdateTestIndex = lwcTestIndexer . onDidUpdateTestIndex ( async ( ) => { allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; const changedTestFileInfo = allTestFileInfo . find ( ( testFileInfo ) => { return ( testFileInfo . testUri . fsPath === testFileUriToChange . fsPath ) ; } ) ; const expectedTestCases = [ { testFsPath : testFileUriToChange . fsPath , testName : 'mockTestCase1' , testResult : { status : TestResultStatus . PASSED } } , { testFsPath : testFileUriToChange . fsPath , testName : 'mockTestCase2' , testResult : { status : TestResultStatus . FAILED } } ] ; expect ( changedTestFileInfo ! . testCasesInfo ! . map ( testCaseInfo => { const { testName , testResult , testUri } = testCaseInfo ; return { testFsPath : testUri . fsPath , testName , testResult } ; } ) ) . to . eql ( expectedTestCases ) ; handleDidUpdateTestIndex . dispose ( ) ; testFileInfoToChange ! . rawTestResults = undefined ; resolve ( ) ; } ) ; onDidChangeEventEmitter . fire ( testFileUriToChange ) ; } ) ; } ) ; it ( 'should update index on test file delete' , async ( ) => { let allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount ) ; const testFileUriToDelete = lwcTests [ 0 ] ; return new Promise ( resolve => { const handleDidUpdateTestIndex = lwcTestIndexer . onDidUpdateTestIndex ( async ( ) => { allTestFileInfo = await lwcTestIndexer . findAllTestFileInfo ( ) ; expect ( allTestFileInfo . length ) . to . equal ( existingTestFileCount - 1 ) ; const deletedTestFileInfo = allTestFileInfo . find ( ( testFileInfo ) => { return ( testFileInfo . testUri . fsPath === testFileUriToDelete . fsPath ) ; } ) ; expect ( deletedTestFileInfo ) . to . be . an ( 'undefined' ) ; handleDidUpdateTestIndex . dispose ( ) ; resolve ( ) ; } ) ; onDidDeleteEventEmitter . fire ( testFileUriToDelete ) ; } ) ; } ) ; } ) ; } ) ;