This commit is contained in:
Joao Moreno 2018-04-18 15:45:27 +02:00
parent 528efc5bbb
commit 7adef9d244
4 changed files with 92 additions and 35 deletions

View file

@ -7,6 +7,7 @@ import { Workbench } from './areas/workbench/workbench';
import * as fs from 'fs';
import * as cp from 'child_process';
import { Code, spawn, SpawnOptions } from './vscode/code';
import { Logger } from './logger';
export enum Quality {
Dev,
@ -19,7 +20,6 @@ export interface ApplicationOptions extends SpawnOptions {
workspacePath: string;
workspaceFilePath: string;
waitTime: number;
verbose: boolean;
}
export class Application {
@ -42,6 +42,10 @@ export class Application {
return this._workbench;
}
get logger(): Logger {
return this.options.logger;
}
get workspacePath(): string {
return this.options.workspacePath;
}
@ -103,7 +107,7 @@ export class Application {
workspacePath: workspaceOrFolder,
userDataDir: this.options.userDataDir,
extensionsPath: this.options.extensionsPath,
verbose: this.options.verbose,
logger: this.options.logger,
extraArgs
});

42
test/smoke/src/logger.ts Normal file
View file

@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { appendFileSync, writeFileSync } from 'fs';
import { format } from 'util';
import { EOL } from 'os';
export interface Logger {
log(message: string, ...args: any[]): void;
}
export class ConsoleLogger implements Logger {
log(message: string, ...args: any[]): void {
console.log('**', message, ...args);
}
}
export class FileLogger implements Logger {
constructor(private path: string) {
writeFileSync(path, '');
}
log(message: string, ...args: any[]): void {
const date = new Date().toISOString();
appendFileSync(this.path, `[${date}] ${format(message, ...args)}${EOL}`);
}
}
export class MultiLogger implements Logger {
constructor(private loggers: Logger[]) { }
log(message: string, ...args: any[]): void {
for (const logger of this.loggers) {
logger.log(message, ...args);
}
}
}

View file

@ -27,7 +27,7 @@ import { setup as setupDataExtensionTests } from './areas/extensions/extensions.
import { setup as setupTerminalTests } from './areas/terminal/terminal.test';
import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test';
import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test';
import { polling } from './vscode/code';
import { MultiLogger, Logger, ConsoleLogger, FileLogger } from './logger';
const tmpDir = tmp.dirSync({ prefix: 't' }) as { name: string; removeCallback: Function; };
const testDataPath = tmpDir.name;
@ -41,7 +41,8 @@ const opts = minimist(args, {
'wait-time',
'test-repo',
'keybindings',
'screenshots'
'screenshots',
'log'
],
boolean: [
'verbose'
@ -238,6 +239,16 @@ async function setup(): Promise<void> {
}
function createApp(quality: Quality): Application {
const loggers: Logger[] = [];
if (opts.verbose) {
loggers.push(new ConsoleLogger());
}
if (opts.log) {
loggers.push(new FileLogger(opts.log));
}
return new Application({
quality,
codePath: opts.build,
@ -246,7 +257,7 @@ function createApp(quality: Quality): Application {
extensionsPath,
workspaceFilePath,
waitTime: parseInt(opts['wait-time'] || '0') || 20,
verbose: opts.verbose
logger: new MultiLogger(loggers)
});
}
@ -289,11 +300,23 @@ describe('Test', () => {
const name = this.currentTest.fullTitle().replace(/[^a-z0-9\-]/ig, '_');
const screenshotPath = path.join(screenshotsPath, `${name}.png`);
console.log('Last poll message: ', polling.lastTimeoutMessage);
if (opts.log) {
app.logger.log('*** Scr eenshot recorded:', screenshotPath);
}
fs.writeFileSync(screenshotPath, buffer);
});
}
if (opts.log) {
beforeEach(async function () {
const app = this.app as Application;
const title = this.currentTest.fullTitle();
app.logger.log('***', title.replace(/./g, '='));
});
}
setupDataLossTests();
setupDataExplorerTests();
setupDataPreferencesTests();

View file

@ -8,6 +8,7 @@ import * as cp from 'child_process';
import * as os from 'os';
import { tmpName } from 'tmp';
import { IDriver, connect as connectDriver, IDisposable, IElement } from './driver';
import { Logger } from '../logger';
const repoPath = path.join(__dirname, '../../../..');
@ -57,13 +58,13 @@ function getBuildOutPath(root: string): string {
}
}
async function connect(child: cp.ChildProcess, outPath: string, handlePath: string, verbose: boolean): Promise<Code> {
async function connect(child: cp.ChildProcess, outPath: string, handlePath: string, logger: Logger): Promise<Code> {
let errCount = 0;
while (true) {
try {
const { client, driver } = await connectDriver(outPath, handlePath);
return new Code(child, client, driver, verbose);
return new Code(child, client, driver, logger);
} catch (err) {
if (++errCount > 50) {
child.kill();
@ -85,7 +86,7 @@ export interface SpawnOptions {
workspacePath: string;
userDataDir: string;
extensionsPath: string;
verbose: boolean;
logger: Logger;
extraArgs?: string[];
}
@ -127,22 +128,14 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
const spawnOptions: cp.SpawnOptions = {};
if (options.verbose) {
spawnOptions.stdio = 'inherit';
}
const child = cp.spawn(electronPath, args, spawnOptions);
instances.add(child);
child.once('exit', () => instances.delete(child));
return connect(child, outPath, handle, options.verbose);
return connect(child, outPath, handle, options.logger);
}
export const polling = {
lastTimeoutMessage: ''
};
async function poll<T>(
fn: () => Promise<T>,
acceptFn: (result: T) => boolean,
@ -159,7 +152,6 @@ async function poll<T>(
let result;
try {
polling.lastTimeoutMessage = timeoutMessage;
result = await fn();
if (acceptFn(result)) {
@ -187,24 +179,20 @@ export class Code {
private process: cp.ChildProcess,
private client: IDisposable,
driver: IDriver,
verbose: boolean
readonly logger: Logger
) {
if (verbose) {
this.driver = new Proxy(driver, {
get(target, prop, receiver) {
if (typeof target[prop] !== 'function') {
return target[prop];
}
return function (...args) {
console.log('** ', prop, ...args.filter(a => typeof a === 'string'));
return target[prop].apply(this, args);
};
this.driver = new Proxy(driver, {
get(target, prop, receiver) {
if (typeof target[prop] !== 'function') {
return target[prop];
}
});
} else {
this.driver = driver;
}
return function (...args) {
logger.log(`${prop}`, ...args.filter(a => typeof a === 'string'));
return target[prop].apply(this, args);
};
}
});
}
async capturePage(): Promise<string> {