Skip to content

Commit b635709

Browse files
authored
chore(recorder): mint page aliases in the language generators (#41728)
1 parent 4650ba4 commit b635709

15 files changed

Lines changed: 110 additions & 99 deletions

File tree

packages/isomorphic/codegen/actions.d.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export type NavigationSignal = BaseSignal & {
142142

143143
export type PopupSignal = BaseSignal & {
144144
name: 'popup',
145-
popupAlias: string,
145+
popupPageGuid: string,
146146
};
147147

148148
export type DownloadSignal = BaseSignal & {
@@ -163,20 +163,15 @@ export type ExpectSignal = BaseSignal & {
163163

164164
export type Signal = NavigationSignal | PopupSignal | DownloadSignal | DialogSignal | ExpectSignal;
165165

166-
export type FrameDescription = {
167-
pageGuid: string;
168-
pageAlias: string;
169-
};
170-
171166
export type ActionInContext = {
172-
frame: FrameDescription;
167+
pageGuid: string;
173168
action: Action;
174169
startTime: number;
175170
endTime?: number;
176171
};
177172

178173
export type SignalInContext = {
179-
frame: FrameDescription;
174+
pageGuid: string;
180175
signal: Signal;
181176
timestamp: number;
182177
};

packages/isomorphic/codegen/csharp.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
3131
name: string;
3232
highlighter = 'csharp' as Language;
3333
_mode: CSharpLanguageMode;
34+
private _pageAliases = new Map<string, string>();
3435

3536
constructor(mode: CSharpLanguageMode) {
3637
if (mode === 'library') {
@@ -51,6 +52,22 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
5152
this._mode = mode;
5253
}
5354

55+
reset() {
56+
this._pageAliases.clear();
57+
}
58+
59+
private _pageAlias(pageGuid: string): string {
60+
let alias = this._pageAliases.get(pageGuid);
61+
if (!alias) {
62+
alias = 'page' + (this._pageAliases.size || '');
63+
// Outside of the library mode, the first page is a class member, the rest are local variables.
64+
if (this._mode !== 'library' && alias === 'page')
65+
alias = 'Page';
66+
this._pageAliases.set(pageGuid, alias);
67+
}
68+
return alias;
69+
}
70+
5471
generateAction(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string {
5572
const action = this._generateActionInner(actionInContext, options);
5673
if (action)
@@ -60,9 +77,10 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
6077

6178
_generateActionInner(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string {
6279
const action = actionInContext.action;
80+
// Resolve before the early return, so that pages are named in the order they are opened.
81+
const pageAlias = this._pageAlias(actionInContext.pageGuid);
6382
if (this._mode !== 'library' && (action.name === 'openPage' || action.name === 'closePage'))
6483
return '';
65-
const pageAlias = this._formatPageAlias(actionInContext.frame.pageAlias);
6684
const formatter = new CSharpFormatter(this._mode === 'library' ? 0 : 8);
6785

6886
if (action.name === 'openPage') {
@@ -94,7 +112,8 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
94112
}
95113

96114
if (signals.popup) {
97-
lines.unshift(`var ${this._formatPageAlias(signals.popup.popupAlias)} = await ${pageAlias}.RunAndWaitForPopupAsync(async () =>\n{`);
115+
const popupAlias = this._pageAlias(signals.popup.popupPageGuid);
116+
lines.unshift(`var ${popupAlias} = await ${pageAlias}.RunAndWaitForPopupAsync(async () =>\n{`);
98117
lines.push(`});`);
99118
}
100119

@@ -107,17 +126,6 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
107126
return formatter.format();
108127
}
109128

110-
private _formatPageAlias(pageAlias: string): string {
111-
if (this._mode === 'library')
112-
return pageAlias;
113-
114-
if (pageAlias === 'page')
115-
return 'Page'; // first page is class member
116-
117-
// other pages are local variables
118-
return pageAlias;
119-
}
120-
121129
private _generateActionCall(subject: string, actionInContext: actions.ActionInContext): string {
122130
const action = actionInContext.action;
123131
switch (action.name) {

packages/isomorphic/codegen/java.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class JavaLanguageGenerator implements LanguageGenerator {
3333
name: string;
3434
highlighter = 'java' as Language;
3535
_mode: JavaLanguageMode;
36+
private _pageAliases = new Map<string, string>();
3637

3738
constructor(mode: JavaLanguageMode) {
3839
if (mode === 'library') {
@@ -47,9 +48,23 @@ export class JavaLanguageGenerator implements LanguageGenerator {
4748
this._mode = mode;
4849
}
4950

51+
reset() {
52+
this._pageAliases.clear();
53+
}
54+
55+
private _pageAlias(pageGuid: string): string {
56+
let alias = this._pageAliases.get(pageGuid);
57+
if (!alias) {
58+
alias = 'page' + (this._pageAliases.size || '');
59+
this._pageAliases.set(pageGuid, alias);
60+
}
61+
return alias;
62+
}
63+
5064
generateAction(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string {
5165
const action = actionInContext.action;
52-
const pageAlias = actionInContext.frame.pageAlias;
66+
// Resolve before the early return, so that pages are named in the order they are opened.
67+
const pageAlias = this._pageAlias(actionInContext.pageGuid);
5368
const offset = this._mode === 'junit' ? 4 : 6;
5469
const formatter = new JavaScriptFormatter(offset);
5570

@@ -76,7 +91,8 @@ export class JavaLanguageGenerator implements LanguageGenerator {
7691
let code = this._generateActionCall(subject, actionInContext);
7792

7893
if (signals.popup) {
79-
code = `Page ${signals.popup.popupAlias} = ${pageAlias}.waitForPopup(() -> {
94+
const popupAlias = this._pageAlias(signals.popup.popupPageGuid);
95+
code = `Page ${popupAlias} = ${pageAlias}.waitForPopup(() -> {
8096
${code}
8197
});`;
8298
}

packages/isomorphic/codegen/javascript.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,34 @@ export class JavaScriptLanguageGenerator implements LanguageGenerator {
2929
name: string;
3030
highlighter = 'javascript' as Language;
3131
private _isTest: boolean;
32+
private _pageAliases = new Map<string, string>();
3233

3334
constructor(isTest: boolean) {
3435
this.id = isTest ? 'playwright-test' : 'javascript';
3536
this.name = isTest ? 'Test Runner' : 'Library';
3637
this._isTest = isTest;
3738
}
3839

40+
reset() {
41+
this._pageAliases.clear();
42+
}
43+
44+
private _pageAlias(pageGuid: string): string {
45+
let alias = this._pageAliases.get(pageGuid);
46+
if (!alias) {
47+
alias = 'page' + (this._pageAliases.size || '');
48+
this._pageAliases.set(pageGuid, alias);
49+
}
50+
return alias;
51+
}
52+
3953
generateAction(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string {
4054
const action = actionInContext.action;
55+
// Resolve before the early return, so that pages are named in the order they are opened.
56+
const pageAlias = this._pageAlias(actionInContext.pageGuid);
4157
if (this._isTest && (action.name === 'openPage' || action.name === 'closePage'))
4258
return '';
4359

44-
const pageAlias = actionInContext.frame.pageAlias;
4560
const formatter = new JavaScriptFormatter(2);
4661

4762
if (action.name === 'openPage') {
@@ -61,15 +76,16 @@ export class JavaScriptLanguageGenerator implements LanguageGenerator {
6176
});`);
6277
}
6378

64-
if (signals.popup)
65-
formatter.add(`const ${signals.popup.popupAlias}Promise = ${pageAlias}.waitForEvent('popup');`);
79+
const popupAlias = signals.popup ? this._pageAlias(signals.popup.popupPageGuid) : undefined;
80+
if (popupAlias)
81+
formatter.add(`const ${popupAlias}Promise = ${pageAlias}.waitForEvent('popup');`);
6682
if (signals.download)
6783
formatter.add(`const download${signals.download.downloadAlias}Promise = ${pageAlias}.waitForEvent('download');`);
6884

6985
formatter.add(this._generateActionCall(subject, actionInContext));
7086

71-
if (signals.popup)
72-
formatter.add(`const ${signals.popup.popupAlias} = await ${signals.popup.popupAlias}Promise;`);
87+
if (popupAlias)
88+
formatter.add(`const ${popupAlias} = await ${popupAlias}Promise;`);
7389
if (signals.download)
7490
formatter.add(`const download${signals.download.downloadAlias} = await download${signals.download.downloadAlias}Promise;`);
7591
if (options.generateExpectSignal && signals.expect)

packages/isomorphic/codegen/jsonl.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ export class JsonlLanguageGenerator implements LanguageGenerator {
2626
name = 'JSONL';
2727
highlighter = 'javascript' as Language;
2828

29+
reset() {
30+
}
31+
2932
generateAction(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string {
3033
const locator = (actionInContext.action as any).selector ? JSON.parse(asLocator('jsonl', (actionInContext.action as any).selector)) : undefined;
3134
const entry = {
3235
...actionInContext.action,
33-
...actionInContext.frame,
36+
pageGuid: actionInContext.pageGuid,
3437
locator,
3538
ariaSnapshot: undefined,
3639
};

packages/isomorphic/codegen/language.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type { LanguageGenerator, LanguageGeneratorOptions } from './types';
2020
import type * as actions from './actions';
2121

2222
export function generateCode(actions: actions.ActionInContext[], languageGenerator: LanguageGenerator, options: LanguageGeneratorOptions) {
23+
languageGenerator.reset();
2324
const header = languageGenerator.generateHeader(options);
2425
const footer = languageGenerator.generateFooter(options.saveStorage);
2526
const actionTexts = actions.map(a => languageGenerator.generateAction(a, options)).filter(Boolean);
@@ -29,7 +30,7 @@ export function generateCode(actions: actions.ActionInContext[], languageGenerat
2930

3031
export function expectSignalAction(actionInContext: actions.ActionInContext, signal: actions.ExpectSignal): actions.ActionInContext {
3132
return {
32-
frame: actionInContext.frame,
33+
pageGuid: actionInContext.pageGuid,
3334
startTime: actionInContext.startTime,
3435
endTime: actionInContext.startTime,
3536
action: {

packages/isomorphic/codegen/python.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class PythonLanguageGenerator implements LanguageGenerator {
3333
private _asyncPrefix: '' | 'async ';
3434
private _isAsync: boolean;
3535
private _isPyTest: boolean;
36+
private _pageAliases = new Map<string, string>();
3637

3738
constructor(isAsync: boolean, isPyTest: boolean) {
3839
this.id = isPyTest ? 'python-pytest' : (isAsync ? 'python-async' : 'python');
@@ -43,12 +44,26 @@ export class PythonLanguageGenerator implements LanguageGenerator {
4344
this._asyncPrefix = isAsync ? 'async ' : '';
4445
}
4546

47+
reset() {
48+
this._pageAliases.clear();
49+
}
50+
51+
private _pageAlias(pageGuid: string): string {
52+
let alias = this._pageAliases.get(pageGuid);
53+
if (!alias) {
54+
alias = 'page' + (this._pageAliases.size || '');
55+
this._pageAliases.set(pageGuid, alias);
56+
}
57+
return alias;
58+
}
59+
4660
generateAction(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string {
4761
const action = actionInContext.action;
62+
// Resolve before the early return, so that pages are named in the order they are opened.
63+
const pageAlias = this._pageAlias(actionInContext.pageGuid);
4864
if (this._isPyTest && (action.name === 'openPage' || action.name === 'closePage'))
4965
return '';
5066

51-
const pageAlias = actionInContext.frame.pageAlias;
5267
const formatter = new PythonFormatter(4);
5368

5469
if (action.name === 'openPage') {
@@ -67,10 +82,11 @@ export class PythonLanguageGenerator implements LanguageGenerator {
6782
let code = `${this._awaitPrefix}${this._generateActionCall(subject, actionInContext)}`;
6883

6984
if (signals.popup) {
70-
code = `${this._asyncPrefix}with ${pageAlias}.expect_popup() as ${signals.popup.popupAlias}_info {
85+
const popupAlias = this._pageAlias(signals.popup.popupPageGuid);
86+
code = `${this._asyncPrefix}with ${pageAlias}.expect_popup() as ${popupAlias}_info {
7187
${code}
7288
}
73-
${signals.popup.popupAlias} = ${this._awaitPrefix}${signals.popup.popupAlias}_info.value`;
89+
${popupAlias} = ${this._awaitPrefix}${popupAlias}_info.value`;
7490
}
7591

7692
if (signals.download) {

packages/isomorphic/codegen/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export interface LanguageGenerator {
4444
groupName: string;
4545
name: string;
4646
highlighter: Language;
47+
reset(): void;
4748
generateHeader(options: LanguageGeneratorOptions): string;
4849
generateAction(actionInContext: actions.ActionInContext, options: LanguageGeneratorOptions): string;
4950
generateFooter(saveStorage: string | undefined): string;

packages/playwright-core/src/server/debugController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ function wireListeners(recorder: Recorder, debugController: DebugController) {
213213
actionsChanged();
214214
});
215215
recorder.on(RecorderEvent.SignalAdded, (signal: actions.SignalInContext) => {
216-
const lastAction = actions.findLast(a => a.frame.pageGuid === signal.frame.pageGuid);
216+
const lastAction = actions.findLast(a => a.pageGuid === signal.pageGuid);
217217
if (lastAction)
218218
lastAction.action.signals.push(signal.signal);
219219
actionsChanged();

0 commit comments

Comments
 (0)