Skip to content

Commit

Permalink
✨ Automatically start the adapter when a Pester test file is opened (#76
Browse files Browse the repository at this point in the history
)

The Pester test adapter will now automatically detect if the active tab or a newly opened file is a Pester test and initialize the adapter without needing to expand the test first in the test adapter.
  • Loading branch information
JustinGrote authored Oct 16, 2021
1 parent dee5619 commit 8bbe081
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 60 deletions.
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function activate(context: ExtensionContext) {
if (psExtensionCodeLensSetting && !suppressCodeLensNotice) {
window
.showInformationMessage(
'The Pester Tests extension recommends disabling the built-in PowerShell extension CodeLens. Would you like to do this?',
'The Pester Tests extension recommends disabling the built-in PowerShell Pester CodeLens. Would you like to do this?',
'Yes',
'Workspace Only',
'No',
Expand Down
145 changes: 86 additions & 59 deletions src/pesterTestController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
TestTag,
Uri,
window,
workspace
workspace,
languages
} from 'vscode'
import { DotnetNamedPipeServer } from './dotnetNamedPipeServer'
import log, { ConsoleLogTransport, VSCodeOutputChannelTransport } from './log'
Expand All @@ -45,6 +46,7 @@ export class PesterTestController implements Disposable {
private powerShellExtensionClient: PowerShellExtensionClient | undefined
private readonly runProfile: TestRunProfile
private readonly debugProfile: TestRunProfile
private initialized = false
constructor(
private readonly powershellExtension: Extension<IPowerShellExtensionClient>,
private readonly context: ExtensionContext,
Expand Down Expand Up @@ -75,6 +77,33 @@ export class PesterTestController implements Disposable {
this.testHandler.bind(this),
true
)

// Watch for pester files to be opened
workspace.onDidOpenTextDocument(doc => {
if (
// Only file support for now
// TODO: Virtual File Support and "hot editing" via scriptblock entry into Pester
doc.uri.scheme !== 'file' ||
!languages.match(this.getPesterRelativePatterns(), doc)
) {
return
}
const testFile = TestFile.getOrCreate(testController, doc.uri)
// TODO: Performance Optimization: Dont discover if the file was previously discovered and not changed
this.resolveHandler(testFile)
})

// Resolves a situation where the extension is loaded but a Pester file is already open
const activeDocument = window.activeTextEditor?.document

if (
activeDocument &&
activeDocument.uri.scheme === 'file' &&
languages.match(this.getPesterRelativePatterns(), activeDocument)
) {
const testFile = TestFile.getOrCreate(testController, activeDocument.uri)
this.resolveHandler(testFile)
}
}

/** Queues up testItems from resolveHandler requests because pester works faster scanning multiple files together **/
Expand All @@ -89,18 +118,22 @@ export class PesterTestController implements Disposable {
testItem: TestItem | undefined,
force?: boolean
): Promise<void> {
// If testitem is undefined, this is a signal to initialize the controller
if (testItem === undefined) {
if (!this.initialized) {
log.info(
'Initializing Pester Test Controller and watching for Pester Files'
)
await this.watchWorkspaces()
this.initialized = true
}

// If testitem is undefined, this is a signal to initialize the controller but not actually do anything, so we exit here.
if (testItem === undefined) {
return
} else {
// Reset any errors previously reported.
testItem.error = undefined
}

// Reset any errors previously reported.
testItem.error = undefined

const testItemData = TestData.get(testItem)
if (!testItemData) {
throw new Error('No matching testItem data found. This is a bug')
Expand Down Expand Up @@ -471,19 +504,14 @@ export class PesterTestController implements Disposable {
}
}

/**
* Starts up filewatchers for each workspace to scan for pester files and add them to the test controller root.
*
* @param {TestController} testController - The test controller to initiate watching on
* @param {Disposable[]} [disposable=[]] - An array to store disposables from the watchers, usually {@link ExtensionContext.subscriptions} to auto-dispose the watchers on unload or cancel
*/
async watchWorkspaces() {
const testController = this.testController
const disposable = this.context.subscriptions
/** Returns a list of relative patterns based on user configuration for matching Pester files in the workspace */
getPesterRelativePatterns() {
const pesterFilePatterns = new Array<RelativePattern>()

if (!workspace.workspaceFolders) {
// TODO: Register event to look for when a workspace folder is added
log.warn('No workspace folders detected.')
return
return pesterFilePatterns
}
const pathToWatch: string[] = workspace
.getConfiguration('pester')
Expand All @@ -492,51 +520,50 @@ export class PesterTestController implements Disposable {
for (const workspaceFolder of workspace.workspaceFolders) {
for (const pathToWatchItem of pathToWatch) {
const pattern = new RelativePattern(workspaceFolder, pathToWatchItem)
const testWatcher = workspace.createFileSystemWatcher(pattern)
const tests = this.testController.items
testWatcher.onDidCreate(uri => {
log.info(`File created: ${uri.toString()}`)
tests.add(TestFile.getOrCreate(testController, uri))
})
testWatcher.onDidDelete(uri => {
log.info(`File deleted: ${uri.toString()}`)
tests.delete(TestFile.getOrCreate(testController, uri).id)
})
testWatcher.onDidChange(uri => {
log.info(`File saved: ${uri.toString()}`)
const savedFile = TestFile.getOrCreate(testController, uri)
this.resolveHandler(savedFile, true).then(() => {
if (
workspace.getConfiguration('pester').get<boolean>('autoRunOnSave')
) {
this.testHandler(
new TestRunRequest([savedFile], undefined, this.runProfile)
)
}
})
pesterFilePatterns.push(pattern)
}
}
return pesterFilePatterns
}

/**
* Starts up filewatchers for each workspace to scan for pester files and add them to the test controller root.
*
* @param {TestController} testController - The test controller to initiate watching on
* @param {Disposable[]} [disposable=[]] - An array to store disposables from the watchers, usually {@link ExtensionContext.subscriptions} to auto-dispose the watchers on unload or cancel
*/
async watchWorkspaces() {
const testController = this.testController
const disposable = this.context.subscriptions
for (const pattern of this.getPesterRelativePatterns()) {
const testWatcher = workspace.createFileSystemWatcher(pattern)
const tests = this.testController.items
testWatcher.onDidCreate(uri => {
log.info(`File created: ${uri.toString()}`)
tests.add(TestFile.getOrCreate(testController, uri))
})
testWatcher.onDidDelete(uri => {
log.info(`File deleted: ${uri.toString()}`)
tests.delete(TestFile.getOrCreate(testController, uri).id)
})
testWatcher.onDidChange(uri => {
log.info(`File saved: ${uri.toString()}`)
const savedFile = TestFile.getOrCreate(testController, uri)
this.resolveHandler(savedFile, true).then(() => {
if (
workspace.getConfiguration('pester').get<boolean>('autoRunOnSave')
) {
this.testHandler(
new TestRunRequest([savedFile], undefined, this.runProfile)
)
}
})
})

// TODO: Fix this for non-file based pester tests and
// workspace.onDidOpenTextDocument(async e => {
// const inScopeFiles = await workspace.findFiles(pattern)
// // Only work on in-scope files
// if (inScopeFiles.indexOf(e.uri) === -1) {
// return
// }
// if (this.testController.resolveHandler === undefined) {
// throw 'onDidOpenTextDocument was called but the testcontroller resolve handler wasnt defined. This is a bug'
// }
// const testFile = TestFile.getOrCreate(testController, e.uri)
// if testFile.
// this.testController.resolveHandler(
// )
// })

const files = await workspace.findFiles(pattern)
for (const file of files) {
log.info('Detected Pester File: ', file.fsPath)
TestFile.getOrCreate(testController, file)
}
const files = await workspace.findFiles(pattern)
for (const file of files) {
log.info('Detected Pester File: ', file.fsPath)
TestFile.getOrCreate(testController, file)
}
}
}
Expand Down

0 comments on commit 8bbe081

Please sign in to comment.