Skip to content

Commit 17f7bc7

Browse files
feat: location info for journey and step (#474)
* feat: location info for journey and step * add comment on line and column check
1 parent 33de607 commit 17f7bc7

File tree

11 files changed

+116
-46
lines changed

11 files changed

+116
-46
lines changed

__tests__/helper.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
rewriteErrorStack,
3434
findPWLogsIndexes,
3535
microSecsToSeconds,
36+
wrapFnWithLocation,
3637
} from '../src/helpers';
3738

3839
it('indent message with seperator', () => {
@@ -133,3 +134,12 @@ it('does not rewrite non playwright errors', () => {
133134
const newNormalStack = rewriteErrorStack(normalStack, indexes);
134135
expect(normalStack).toStrictEqual(newNormalStack);
135136
});
137+
138+
it('location info on execution', () => {
139+
const checkLoc = wrapFnWithLocation(location => {
140+
return location;
141+
});
142+
// line no and column no will not match as we are using
143+
// ts-jest preset to transpile code.
144+
expect(checkLoc().file).toBe(__filename);
145+
});

package-lock.json

Lines changed: 8 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"author": "",
3939
"license": "MIT",
4040
"dependencies": {
41+
"@cspotcode/source-map-support": "^0.7.0",
4142
"commander": "^9.0.0",
4243
"deepmerge": "^4.2.2",
4344
"expect": "^27.0.2",
@@ -48,8 +49,7 @@
4849
"sharp": "^0.30.1",
4950
"snakecase-keys": "^3.2.1",
5051
"sonic-boom": "^2.6.0",
51-
"source-map-support": "^0.5.21",
52-
"ts-node": "^10.5.0",
52+
"ts-node": "^10.7.0",
5353
"typescript": "^4.5.5"
5454
},
5555
"devDependencies": {

src/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ async function prepareSuites(inputs: string[]) {
141141
compilerOptions: {
142142
esModuleInterop: true,
143143
allowJs: true,
144-
target: 'es2018',
144+
target: 'es2020',
145145
},
146146
});
147147

src/common_types.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ import { Step } from './dsl';
3636
import { reporters } from './reporters';
3737

3838
export type VoidCallback = () => void;
39-
export type Params = Record<string, any>;
40-
export type NetworkConditions = {
41-
offline: boolean;
42-
downloadThroughput: number;
43-
uploadThroughput: number;
44-
latency: number;
39+
export type Location = {
40+
file: string;
41+
line: number;
42+
column: number;
4543
};
44+
45+
export type Params = Record<string, any>;
4646
export type HooksArgs = {
4747
env: string;
4848
params: Params;
@@ -51,6 +51,13 @@ export type HooksCallback = (args: HooksArgs) => void;
5151
export type StatusValue = 'succeeded' | 'failed' | 'skipped';
5252
export type Reporters = keyof typeof reporters;
5353

54+
export type NetworkConditions = {
55+
offline: boolean;
56+
downloadThroughput: number;
57+
uploadThroughput: number;
58+
latency: number;
59+
};
60+
5461
export type Driver = {
5562
browser: ChromiumBrowser;
5663
context: ChromiumBrowserContext;

src/core/index.ts

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626
import { Journey, JourneyCallback, JourneyOptions } from '../dsl';
2727
import Runner from './runner';
28-
import { VoidCallback, HooksCallback } from '../common_types';
28+
import { VoidCallback, HooksCallback, Location } from '../common_types';
29+
import { wrapFnWithLocation } from '../helpers';
2930
import { log } from './logger';
3031

3132
/**
@@ -39,23 +40,28 @@ if (!global[SYNTHETICS_RUNNER]) {
3940

4041
export const runner: Runner = global[SYNTHETICS_RUNNER];
4142

42-
export const journey = (
43-
options: JourneyOptions | string,
44-
callback: JourneyCallback
45-
) => {
46-
log(`register journey: ${JSON.stringify(options)}`);
47-
if (typeof options === 'string') {
48-
options = { name: options, id: options };
43+
export const journey = wrapFnWithLocation(
44+
(
45+
location: Location,
46+
options: JourneyOptions | string,
47+
callback: JourneyCallback
48+
) => {
49+
log(`register journey: ${JSON.stringify(options)}`);
50+
if (typeof options === 'string') {
51+
options = { name: options, id: options };
52+
}
53+
const j = new Journey(options, callback, location);
54+
runner.addJourney(j);
55+
return j;
4956
}
50-
const j = new Journey(options, callback);
51-
runner.addJourney(j);
52-
return j;
53-
};
57+
);
5458

55-
export const step = (name: string, callback: VoidCallback) => {
56-
log(`register step: ${name}`);
57-
return runner.currentJourney?.addStep(name, callback);
58-
};
59+
export const step = wrapFnWithLocation(
60+
(location: Location, name: string, callback: VoidCallback) => {
61+
log(`register step: ${name}`);
62+
return runner.currentJourney?.addStep(name, callback, location);
63+
}
64+
);
5965

6066
export const beforeAll = (callback: HooksCallback) => {
6167
runner.addHook('beforeAll', callback);

src/dsl/journey.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import { Browser, Page, BrowserContext, CDPSession } from 'playwright-chromium';
2727
import micromatch, { isMatch } from 'micromatch';
2828
import { Step } from './step';
29-
import { VoidCallback, HooksCallback, Params } from '../common_types';
29+
import { VoidCallback, HooksCallback, Params, Location } from '../common_types';
3030

3131
export type JourneyOptions = {
3232
name: string;
@@ -49,18 +49,24 @@ export class Journey {
4949
id?: string;
5050
tags?: string[];
5151
callback: JourneyCallback;
52+
location?: Location;
5253
steps: Step[] = [];
5354
hooks: Hooks = { before: [], after: [] };
5455

55-
constructor(options: JourneyOptions, callback: JourneyCallback) {
56+
constructor(
57+
options: JourneyOptions,
58+
callback: JourneyCallback,
59+
location?: Location
60+
) {
5661
this.name = options.name;
5762
this.id = options.id || options.name;
5863
this.tags = options.tags;
5964
this.callback = callback;
65+
this.location = location;
6066
}
6167

62-
addStep(name: string, callback: VoidCallback) {
63-
const step = new Step(name, this.steps.length + 1, callback);
68+
addStep(name: string, callback: VoidCallback, location?: Location) {
69+
const step = new Step(name, this.steps.length + 1, callback, location);
6470
this.steps.push(step);
6571
return step;
6672
}

src/dsl/step.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,23 @@
2323
*
2424
*/
2525

26-
import { VoidCallback } from '../common_types';
26+
import { Location, VoidCallback } from '../common_types';
2727

2828
export class Step {
2929
name: string;
3030
index: number;
3131
callback: VoidCallback;
32+
location?: Location;
3233

33-
constructor(name: string, index: number, callback: VoidCallback) {
34+
constructor(
35+
name: string,
36+
index: number,
37+
callback: VoidCallback,
38+
location: Location
39+
) {
3440
this.name = name;
3541
this.index = index;
3642
this.callback = callback;
43+
this.location = location;
3744
}
3845
}

src/helpers.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ import { resolve, join, dirname } from 'path';
2929
import fs from 'fs';
3030
import { promisify } from 'util';
3131
import { performance } from 'perf_hooks';
32-
import { HooksArgs, HooksCallback, NetworkConditions } from './common_types';
32+
import sourceMapSupport from '@cspotcode/source-map-support';
33+
import {
34+
HooksArgs,
35+
HooksCallback,
36+
NetworkConditions,
37+
Location,
38+
} from './common_types';
3339

3440
const lstatAsync = promisify(fs.lstat);
3541
const readdirAsync = promisify(fs.readdir);
@@ -315,3 +321,36 @@ export function parseNetworkConditions(args: string): NetworkConditions {
315321

316322
return networkConditions;
317323
}
324+
325+
// default stack trace limit
326+
const dstackTraceLimit = 10;
327+
328+
// Uses the V8 Stacktrace API to get the function location
329+
// information - https://v8.dev/docs/stack-trace-api#customizing-stack-traces
330+
export function wrapFnWithLocation<A extends unknown[], R>(
331+
func: (location: Location, ...args: A) => R
332+
): (...args: A) => R {
333+
return (...args) => {
334+
const _prepareStackTrace = Error.prepareStackTrace;
335+
Error.prepareStackTrace = (_, stackFrames) => {
336+
// Deafult CallSite would not map to the original transpiled source
337+
// from ts-node properly, So we wrap it with the library that knows
338+
// how to retrive those source-map for the transpiled code
339+
const frame: NodeJS.CallSite = sourceMapSupport.wrapCallSite(
340+
stackFrames[1]
341+
);
342+
return {
343+
file: frame.getFileName(),
344+
line: frame.getLineNumber(),
345+
column: frame.getColumnNumber(),
346+
};
347+
};
348+
Error.stackTraceLimit = 2;
349+
const obj: { stack: Location } = {} as any;
350+
Error.captureStackTrace(obj);
351+
const location = obj.stack;
352+
Error.stackTraceLimit = dstackTraceLimit;
353+
Error.prepareStackTrace = _prepareStackTrace;
354+
return func(location, ...args);
355+
};
356+
}

src/index.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,8 @@
2525

2626
import { runner } from './core';
2727
import { RunOptions } from './core/runner';
28-
import sourceMapSupport from 'source-map-support';
2928

3029
export async function run(options: RunOptions) {
31-
/**
32-
* Install source map support
33-
*/
34-
sourceMapSupport.install({
35-
environment: 'node',
36-
});
37-
3830
try {
3931
return await runner.run(options);
4032
} catch (e) {

0 commit comments

Comments
 (0)