Skip to content
This repository has been archived by the owner on Dec 6, 2022. It is now read-only.

[Do not merge] Dummy PR to test fixes for the CI tests #853

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,18 @@
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"env": {
// TEST_DA_PORT: Enable this to debug the debug-adapter while the tests are running (The test will look for a debug-adapter server on port 4712 instead of launching a new one)
// "TEST_DA_PORT": "4712",
"TEST_DA_PORT": "4712",
// TEST_TIMEOUT_MULTIPLIER: The tests have long timeouts for the CI server. While debugging locally it's sometimes useful to reduce the timeouts, to be able to run all the tests faster when they are failing. This value is a multiplier that will be applied to all timeouts using during the tests... (Work in progress)
"TEST_TIMEOUT_MULTIPLIER": "0.4"
"TEST_TIMEOUT_MULTIPLIER": "0.4",
// TEST_DA_HIDE_WINDOWS: Enable this to hinde the windows that the test create (e.g.: Chrome windows, and Power Shell windows)
// "TEST_DA_HIDE_WINDOWS": "true",
},
"args": [
"--require", "source-map-support/register",
"-u", "tdd",
"--timeout", "999999",
"--colors",
"--grep", "",
"--grep", "Hit count breakpoints on a React project",
"--reporter", "node_modules/vscode-chrome-debug-core-testsupport/out/loggingReporter.js",
"${workspaceFolder}/out/test/int/**/*.test.js",
],
Expand Down
6 changes: 3 additions & 3 deletions test/int/core-v2/chrome/collections/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import { ValidatedMultiMap } from './validatedMultiMap';

export function groupByKey<T, K>(elements: T[], obtainKey: (element: T) => K): ValidatedMultiMap<K, T> {
const groupped = ValidatedMultiMap.empty<K, T>();
elements.forEach(element => groupped.add(obtainKey(element), element));
return groupped;
const grouped = ValidatedMultiMap.empty<K, T>();
elements.forEach(element => grouped.add(obtainKey(element), element));
return grouped;
}

export function determineOrderingOfStrings(left: string, right: string): number {
Expand Down
75 changes: 50 additions & 25 deletions test/int/core-v2/chrome/logging/methodsCalledLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import * as _ from 'lodash';
import * as path from 'path';
import { printTopLevelObjectDescription } from './printObjectDescription';
import { logger } from 'vscode-debugadapter';

Expand All @@ -24,18 +25,21 @@ export class ReplacementInstruction {
export interface IMethodsCalledLoggerConfiguration {
readonly replacements: ReplacementInstruction[];

decideWhetherToWrapMethodResult(methodName: string | symbol | number, args: unknown[], result: unknown, wrapWithName: (name: string) => void): void;
decideWhetherToWrapEventEmitterListener(receiverName: string, methodName: string | symbol | number, args: unknown[], wrapWithName: (name: string) => void): void;
customizeResult(methodName: string | symbol | number, args: unknown[], result: unknown): unknown;
customizeArgumentsBeforeCall(receiverName: string, methodName: string | symbol | number, args: unknown[]): void;
}

export class MethodsCalledLoggerConfiguration implements IMethodsCalledLoggerConfiguration {

public constructor(public readonly containerName: string, private _replacements: ReplacementInstruction[]) { }

public decideWhetherToWrapMethodResult(_methodName: string | symbol | number, _args: unknown[], _result: unknown, _wrapWithName: (name: string) => void): void { }
public decideWhetherToWrapEventEmitterListener(receiverName: string, methodName: string | symbol | number, args: unknown[], wrapWithName: (name: string) => void): void {
if (methodName === 'on') {
wrapWithName(`(${receiverName} emits ${args[0]})`);
public customizeResult(_methodName: string | symbol | number, _args: unknown[], result: unknown): unknown {
return result;
}

public customizeArgumentsBeforeCall(receiverName: string, methodName: string | symbol | number, args: object[]): void {
if (methodName === 'on' && args.length >= 2) {
args[1] = new MethodsCalledLogger(this, args[1], `(${receiverName} emits ${args[0]})`).wrapped();
}
}

Expand All @@ -62,42 +66,34 @@ export class MethodsCalledLogger<T extends object> {
const originalPropertyValue = target[propertyKey];
if (typeof originalPropertyValue === 'function') {
return (...args: any) => {
const callId = this.generateCallId();
try {
if (propertyKey === 'on' && args.length >= 2) {
let listenerPossiblyWrapped = args[1];
this._configuration.decideWhetherToWrapEventEmitterListener(this._objectToWrapName, propertyKey, args, name => listenerPossiblyWrapped = new MethodsCalledLogger(this._configuration, args[1], name).wrapped());
args[1] = listenerPossiblyWrapped;
}

this.logCallStart(propertyKey, args, callId);
this._configuration.customizeArgumentsBeforeCall(this._objectToWrapName, propertyKey, args);
const result = originalPropertyValue.apply(target, args);
if (!result || !result.then) {
this.logCall(propertyKey, Synchronicity.Sync, args, Outcome.Succesful, result);
this.logCall(propertyKey, Synchronicity.Sync, args, Outcome.Succesful, result, callId);
if (result === target) {
return receiver;
} else {
let resultPossiblyWrapped = result;
this._configuration.decideWhetherToWrapMethodResult(propertyKey, args, result, name => resultPossiblyWrapped = new MethodsCalledLogger(this._configuration, result, name).wrapped());
return resultPossiblyWrapped;
return this._configuration.customizeResult(propertyKey, args, result);
}
} else {
const callId = this.generateCallId();
this.logCallStart(propertyKey, args, callId);
this.logSyncPartFinished(propertyKey, args, callId);
return result.then((promiseResult: unknown) => {
this.logCall(propertyKey, Synchronicity.Async, args, Outcome.Succesful, promiseResult, callId);
if (promiseResult === target) {
return receiver;
} else {
let resultPossiblyWrapped = promiseResult;
this._configuration.decideWhetherToWrapMethodResult(propertyKey, args, promiseResult, name => resultPossiblyWrapped = new MethodsCalledLogger(this._configuration, <object>promiseResult, name).wrapped());
return resultPossiblyWrapped;
return this._configuration.customizeResult(propertyKey, args, promiseResult);
}
}, (error: unknown) => {
this.logCall(propertyKey, Synchronicity.Async, args, Outcome.Failure, error, callId);
return Promise.reject(error);
});
}
} catch (exception) {
this.logCall(propertyKey, Synchronicity.Sync, args, Outcome.Failure, exception);
this.logCall(propertyKey, Synchronicity.Sync, args, Outcome.Failure, exception, callId);
throw exception;
}
};
Expand Down Expand Up @@ -126,13 +122,42 @@ export class MethodsCalledLogger<T extends object> {
return `${synchronicity === Synchronicity.Sync ? '' : ' async'}`;
}

/** Returns the test file and line that the code is currently executing e.g.:
* < >
* [22:23:28.468 UTC] START 10026: hitCountBreakpointTests.test.ts:34:2 | #incrementBtn.click()
*/
// TODO: Figure out how to integrate this with V2. We don't want to do this for production logging because new Error().stack is slow
private getTestFileAndLine(): string {
const stack = new Error().stack;
if (stack) {
const stackLines = stack.split('\n');
const testCaseLine = stackLines.find(line => line.indexOf('test.ts') >= 0);
if (testCaseLine) {
const filenameAndLine = testCaseLine.lastIndexOf(path.sep);
if (filenameAndLine >= 0) {
const fileNameAndLineNumber = testCaseLine.substring(filenameAndLine + 1, testCaseLine.length - 2);
return `${fileNameAndLineNumber} | `;
}
}
}

return '';
}

private logCallStart(propertyKey: PropertyKey, methodCallArguments: any[], callId: number): void {
const message = `START ${callId}: ${this.printMethodCall(propertyKey, methodCallArguments)}`;
const getTestFileAndLine = this.getTestFileAndLine();
const message = `START ${callId}: ${getTestFileAndLine}${this.printMethodCall(propertyKey, methodCallArguments)}`;
logger.verbose(message);
}

private logSyncPartFinished(propertyKey: PropertyKey, methodCallArguments: any[], callId: number): void {
const getTestFileAndLine = this.getTestFileAndLine();
const message = `PROMISE-RETURNED ${callId}: ${getTestFileAndLine}${this.printMethodCall(propertyKey, methodCallArguments)}`;
logger.verbose(message);
}

private logCall(propertyKey: PropertyKey, synchronicity: Synchronicity, methodCallArguments: any[], outcome: Outcome, resultOrException: unknown, callId?: number): void {
const endPrefix = callId ? `END ${callId}: ` : '';
private logCall(propertyKey: PropertyKey, synchronicity: Synchronicity, methodCallArguments: any[], outcome: Outcome, resultOrException: unknown, callId: number): void {
const endPrefix = callId ? `END ${callId}: ` : '';
const message = `${endPrefix}${this.printMethodCall(propertyKey, methodCallArguments)} ${this.printMethodSynchronicity(synchronicity)} ${this.printMethodResponse(outcome, resultOrException)}`;
logger.verbose(message);
}
Expand Down
6 changes: 3 additions & 3 deletions test/int/featureBasedSuits/hitCountBreakpointTests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ puppeteerSuite('Hit count breakpoints on a React project', reactTestSpecificatio

await incBtn.click();

await breakpoints.waitAndAssertNotPaused();
await breakpoints.waitAndAssertNoMoreEvents();

await setStateBreakpoint.unset();
});
Expand Down Expand Up @@ -70,7 +70,7 @@ puppeteerSuite('Hit count breakpoints on a React project', reactTestSpecificatio

await incBtn.click();

await breakpoints.waitAndAssertNotPaused();
await breakpoints.waitAndAssertNoMoreEvents();

await setStateBreakpoint.unset();
await setNewValBreakpoint.unset();
Expand Down Expand Up @@ -111,7 +111,7 @@ puppeteerSuite('Hit count breakpoints on a React project', reactTestSpecificatio

await incBtn.click();

await breakpoints.waitAndAssertNotPaused();
await breakpoints.waitAndAssertNoMoreEvents();

await counterBreakpoints.batch(async () => {
await setStateBreakpoint.unset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { puppeteerSuite, puppeteerTest } from '../puppeteer/puppeteerSuite';
import { reactWithLoopTestSpecification } from '../resources/resourceProjects';
import { BreakpointsWizard as BreakpointsWizard } from '../wizards/breakpoints/breakpointsWizard';
import { expect } from 'chai';
import { logger } from 'vscode-debugadapter';

puppeteerSuite('Hit count breakpoints combinations', reactWithLoopTestSpecification, (suiteContext) => {
interface IConditionConfiguration {
Expand Down Expand Up @@ -70,16 +71,17 @@ puppeteerSuite('Hit count breakpoints combinations', reactWithLoopTestSpecificat
* the value of this variable to validate that a bp with = 12 paused on the 12th iteration rather than on the 1st one
* (The breakpoint is located in the same place in both iterations, so we need to use state to differenciate between those two cases)
*/
await setStateBreakpoint.assertIsHitThenResume({ variables: { 'iterationNumber': `${nextIterationToPause}` } });
await setStateBreakpoint.assertIsHitThenResume({ variables: { local_contains: { iterationNumber: nextIterationToPause } } });
}

logger.log(`No more pauses afterwards = ${conditionConfiguration.noMorePausesAfterwards}`);
if (conditionConfiguration.noMorePausesAfterwards) {
await breakpoints.waitAndAssertNotPaused();
await breakpoints.waitAndAssertNoMoreEvents();
await setStateBreakpoint.unset();
} else {
await breakpoints.waitUntilPaused(setStateBreakpoint);
await breakpoints.waitAndConsumePausedEvent(setStateBreakpoint);
await setStateBreakpoint.unset();
await suiteContext.debugClient.continueRequest();
await breakpoints.resume();
}

await buttonClicked;
Expand Down
46 changes: 46 additions & 0 deletions test/int/featureBasedSuits/variablesScopes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { TestProjectSpec } from '../framework/frameworkTestSupport';
import { VariablesWizard } from '../wizards/variables/variablesWizard';
import { LaunchProject } from '../fixtures/launchProject';
import { testUsing } from '../fixtures/testUsing';

// Scopes' kinds: 'global' | 'local' | 'with' | 'closure' | 'catch' | 'block' | 'script' | 'eval' | 'module'
// TODO: Test several scopes at the same time. They can be repeated, and the order does matter
suite('Variables scopes', function () {
testUsing('local', context => LaunchProject.create(context, TestProjectSpec.fromTestPath('variablesScopes/localScope')), async (launchProject) => {
await launchProject.pausedWizard.waitUntilPausedOnDebuggerStatement();

await new VariablesWizard(launchProject.debugClient).assertTopFrameVariablesAre({
local: `
this = Window (Object)
arguments = Arguments(0) [] (Object)
b = body {text: "", link: "", vLink: "", …} (Object)
bool = true (boolean)
buffer = ArrayBuffer(8) {} (Object)
buffView = Int32Array(2) [234, 0] (Object)
consoleDotLog = function consoleDotLog(m) { … } (Function)
e = Error: hi (Object)
element = body {text: "", link: "", vLink: "", …} (Object)
fn = () => { … } (Function)
fn2 = function () { … } (Function)
globalCode = "page loaded" (string)
inf = Infinity (number)
infStr = "Infinity" (string)
longStr = "this is a\nstring with\nnewlines" (string)
m = Map(1) {} (Object)
manyPropsObj = Object {0: 1, 1: 3, 2: 5, …} (Object)
myVar = Object {num: 1, str: "Global", obj: Object, …} (Object)
nan = NaN (number)
obj = Object {a: 2, thing: <accessor>} (Object)
qqq = undefined (undefined)
r = /^asdf.*$/g {lastIndex: 0} (Object)
s = Symbol(hi) (symbol)
str = "hello" (string)
xyz = 4 (number)`}
);
});
});
8 changes: 7 additions & 1 deletion test/int/fixtures/launchProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { LaunchPuppeteer } from '../puppeteer/launchPuppeteer';
import { ExtendedDebugClient } from 'vscode-chrome-debug-core-testsupport';
import { Page, Browser } from 'puppeteer';
import { ITestCallbackContext, IBeforeAndAfterContext } from 'mocha';
import { PausedWizard } from '../wizards/pausedWizard';

/** Perform all the steps neccesary to launch a particular project such as:
* - Default fixture/setup
Expand All @@ -21,14 +22,18 @@ export class LaunchProject implements IFixture {
private constructor(
private readonly _defaultFixture: DefaultFixture,
private readonly _launchWebServer: LaunchWebServer,
public readonly pausedWizard: PausedWizard,
private readonly _launchPuppeteer: LaunchPuppeteer) { }

public static async create(testContext: IBeforeAndAfterContext | ITestCallbackContext, testSpec: TestProjectSpec): Promise<LaunchProject> {
const launchWebServer = await LaunchWebServer.launch(testSpec);
const defaultFixture = await DefaultFixture.create(testContext);

// We need to create the PausedWizard before launching the debuggee to listen to all events and avoid race conditions
const pausedWizard = PausedWizard.forClient(defaultFixture.debugClient);

const launchPuppeteer = await LaunchPuppeteer.create(defaultFixture.debugClient, launchWebServer.launchConfig);
return new LaunchProject(defaultFixture, launchWebServer, launchPuppeteer);
return new LaunchProject(defaultFixture, launchWebServer, pausedWizard, launchPuppeteer);
}

/** Client for the debug adapter being used for this test */
Expand All @@ -51,6 +56,7 @@ export class LaunchProject implements IFixture {
}

public async cleanUp(): Promise<void> {
await this.pausedWizard.waitAndAssertNoMoreEvents();
await this._defaultFixture.cleanUp(); // Disconnect the debug-adapter first
await this._launchPuppeteer.cleanUp(); // Then disconnect puppeteer and close chrome
await this._launchWebServer.cleanUp(); // Finally disconnect the web-server
Expand Down
4 changes: 4 additions & 0 deletions test/int/fixtures/launchWebServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export class LaunchWebServer implements IFixture {
return Object.assign({}, this._testSpec.props.launchConfig, { url: this.url.toString() });
}

public get port(): number {
return this._server.address().port;
}

public async cleanUp(): Promise<void> {
await closeServer(this._server);
}
Expand Down
Loading