feat(codegen): add NUnit/MSTest (#16803)
This commit is contained in:
Родитель
2c1723b6f5
Коммит
74ab343e2b
|
@ -69,7 +69,7 @@ Examples:
|
|||
commandWithOpenOptions('codegen [url]', 'open page and generate code for user actions',
|
||||
[
|
||||
['-o, --output <file name>', 'saves the generated script to a file'],
|
||||
['--target <language>', `language to generate, one of javascript, test, python, python-async, pytest, csharp, java`, language()],
|
||||
['--target <language>', `language to generate, one of javascript, test, python, python-async, pytest, csharp, csharp-mstest, csharp-nunit, java`, language()],
|
||||
['--save-trace <filename>', 'record a trace for the session and save it to a file'],
|
||||
]).action(function(url, options) {
|
||||
codegen(options, url, options.target, options.output).catch(logErrorAndExit);
|
||||
|
|
|
@ -362,12 +362,14 @@ class ContextRecorder extends EventEmitter {
|
|||
setOutput(language: string, outputFile: string | undefined) {
|
||||
const languages = new Set([
|
||||
new JavaLanguageGenerator(),
|
||||
new JavaScriptLanguageGenerator(false),
|
||||
new JavaScriptLanguageGenerator(true),
|
||||
new PythonLanguageGenerator(false, true),
|
||||
new PythonLanguageGenerator(false, false),
|
||||
new PythonLanguageGenerator(true, false),
|
||||
new CSharpLanguageGenerator(),
|
||||
new JavaScriptLanguageGenerator(/* isPlaywrightTest */false),
|
||||
new JavaScriptLanguageGenerator(/* isPlaywrightTest */true),
|
||||
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */true),
|
||||
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */false),
|
||||
new PythonLanguageGenerator(/* isAsync */true, /* isPytest */false),
|
||||
new CSharpLanguageGenerator('mstest'),
|
||||
new CSharpLanguageGenerator('nunit'),
|
||||
new CSharpLanguageGenerator('library'),
|
||||
]);
|
||||
const primaryLanguage = [...languages].find(l => l.id === language);
|
||||
if (!primaryLanguage)
|
||||
|
|
|
@ -25,17 +25,46 @@ import { toModifiers } from './utils';
|
|||
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
||||
import deviceDescriptors from '../deviceDescriptors';
|
||||
|
||||
type CSharpLanguageMode = 'library' | 'mstest' | 'nunit';
|
||||
|
||||
export class CSharpLanguageGenerator implements LanguageGenerator {
|
||||
id = 'csharp';
|
||||
groupName = '.NET';
|
||||
name = 'Library C#';
|
||||
id: string;
|
||||
groupName = '.NET C#';
|
||||
name: string;
|
||||
highlighter = 'csharp';
|
||||
_mode: CSharpLanguageMode;
|
||||
|
||||
constructor(mode: CSharpLanguageMode) {
|
||||
if (mode === 'library') {
|
||||
this.name = 'Library';
|
||||
this.id = 'csharp';
|
||||
} else if (mode === 'mstest') {
|
||||
this.name = 'MSTest';
|
||||
this.id = 'csharp-mstest';
|
||||
} else if (mode === 'nunit') {
|
||||
this.name = 'NUnit';
|
||||
this.id = 'csharp-nunit';
|
||||
} else {
|
||||
throw new Error(`Unknown C# language mode: ${mode}`);
|
||||
}
|
||||
this._mode = mode;
|
||||
}
|
||||
|
||||
generateAction(actionInContext: ActionInContext): string {
|
||||
const action = this._generateActionInner(actionInContext);
|
||||
if (action)
|
||||
return action + '\n';
|
||||
return '';
|
||||
}
|
||||
|
||||
_generateActionInner(actionInContext: ActionInContext): string {
|
||||
const action = actionInContext.action;
|
||||
const pageAlias = actionInContext.frame.pageAlias;
|
||||
if (this._mode !== 'library' && (action.name === 'openPage' || action.name === 'closePage'))
|
||||
return '';
|
||||
let pageAlias = actionInContext.frame.pageAlias;
|
||||
if (this._mode !== 'library')
|
||||
pageAlias = pageAlias.replace('page', 'Page');
|
||||
const formatter = new CSharpFormatter(8);
|
||||
formatter.newLine();
|
||||
formatter.add('// ' + actionTitle(action));
|
||||
|
||||
if (action.name === 'openPage') {
|
||||
|
@ -137,6 +166,12 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
|
|||
}
|
||||
|
||||
generateHeader(options: LanguageGeneratorOptions): string {
|
||||
if (this._mode === 'library')
|
||||
return this.generateStandaloneHeader(options);
|
||||
return this.generateTestRunnerHeader(options);
|
||||
}
|
||||
|
||||
generateStandaloneHeader(options: LanguageGeneratorOptions): string {
|
||||
const formatter = new CSharpFormatter(0);
|
||||
formatter.add(`
|
||||
using Microsoft.Playwright;
|
||||
|
@ -150,6 +185,30 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
|
|||
using var playwright = await Playwright.CreateAsync();
|
||||
await using var browser = await playwright.${toPascal(options.browserName)}.LaunchAsync(${formatObject(options.launchOptions, ' ', 'BrowserTypeLaunchOptions')});
|
||||
var context = await browser.NewContextAsync(${formatContextOptions(options.contextOptions, options.deviceName)});`);
|
||||
formatter.newLine();
|
||||
return formatter.format();
|
||||
}
|
||||
|
||||
generateTestRunnerHeader(options: LanguageGeneratorOptions): string {
|
||||
const formatter = new CSharpFormatter(0);
|
||||
formatter.add(`
|
||||
using Microsoft.Playwright.${this._mode === 'nunit' ? 'NUnit' : 'MSTest'};
|
||||
using Microsoft.Playwright;
|
||||
|
||||
${this._mode === 'nunit' ? '[Parallelizable(ParallelScope.Self)]' : '[TestClass]'}
|
||||
public class Tests : PageTest
|
||||
{`);
|
||||
const formattedContextOptions = formatContextOptions(options.contextOptions, options.deviceName);
|
||||
if (formattedContextOptions) {
|
||||
formatter.add(`public override BrowserNewContextOptions ContextOptions()
|
||||
{
|
||||
return ${formattedContextOptions};
|
||||
}`);
|
||||
formatter.newLine();
|
||||
}
|
||||
formatter.add(` [${this._mode === 'nunit' ? 'Test' : 'TestMethod'}]
|
||||
public async Task MyTest()
|
||||
{`);
|
||||
return formatter.format();
|
||||
}
|
||||
|
||||
|
|
|
@ -193,3 +193,80 @@ test('should work with --save-har', async ({ runCLI }, testInfo) => {
|
|||
const json = JSON.parse(fs.readFileSync(harFileName, 'utf-8'));
|
||||
expect(json.log.creator.name).toBe('Playwright');
|
||||
});
|
||||
|
||||
for (const testFramework of ['nunit', 'mstest'] as const) {
|
||||
test(`should not print context options method override in ${testFramework} if no options were passed`, async ({ runCLI }) => {
|
||||
const cli = runCLI([`--target=csharp-${testFramework}`, emptyHTML]);
|
||||
await cli.waitFor(`Page.GotoAsync("${emptyHTML}")`);
|
||||
expect(cli.text()).not.toContain('public override BrowserNewContextOptions ContextOptions()');
|
||||
});
|
||||
|
||||
test(`should print context options method override in ${testFramework} if options were passed`, async ({ runCLI }) => {
|
||||
const cli = runCLI([`--target=csharp-${testFramework}`, '--color-scheme=dark', emptyHTML]);
|
||||
await cli.waitFor(`Page.GotoAsync("${emptyHTML}")`);
|
||||
expect(cli.text()).toContain(` public override BrowserNewContextOptions ContextOptions()
|
||||
{
|
||||
return new BrowserNewContextOptions
|
||||
{
|
||||
ColorScheme = ColorScheme.Dark,
|
||||
};
|
||||
}
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
test(`should print a valid basic program in mstest`, async ({ runCLI }) => {
|
||||
const cli = runCLI([`--target=csharp-mstest`, '--color-scheme=dark', emptyHTML]);
|
||||
await cli.waitFor(`Page.GotoAsync("${emptyHTML}")`);
|
||||
const expected = `using Microsoft.Playwright.MSTest;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
[TestClass]
|
||||
public class Tests : PageTest
|
||||
{
|
||||
public override BrowserNewContextOptions ContextOptions()
|
||||
{
|
||||
return new BrowserNewContextOptions
|
||||
{
|
||||
ColorScheme = ColorScheme.Dark,
|
||||
};
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task MyTest()
|
||||
{
|
||||
// Go to ${emptyHTML}
|
||||
await Page.GotoAsync("${emptyHTML}");
|
||||
|
||||
}
|
||||
}`;
|
||||
expect(cli.text()).toContain(expected);
|
||||
});
|
||||
|
||||
test(`should print a valid basic program in nunit`, async ({ runCLI }) => {
|
||||
const cli = runCLI([`--target=csharp-nunit`, '--color-scheme=dark', emptyHTML]);
|
||||
await cli.waitFor(`Page.GotoAsync("${emptyHTML}")`);
|
||||
const expected = `using Microsoft.Playwright.NUnit;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
[Parallelizable(ParallelScope.Self)]
|
||||
public class Tests : PageTest
|
||||
{
|
||||
public override BrowserNewContextOptions ContextOptions()
|
||||
{
|
||||
return new BrowserNewContextOptions
|
||||
{
|
||||
ColorScheme = ColorScheme.Dark,
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task MyTest()
|
||||
{
|
||||
// Go to ${emptyHTML}
|
||||
await Page.GotoAsync("${emptyHTML}");
|
||||
|
||||
}
|
||||
}`;
|
||||
expect(cli.text()).toContain(expected);
|
||||
});
|
||||
|
|
|
@ -35,6 +35,8 @@ const codegenLang2Id: Map<string, string> = new Map([
|
|||
['Python Async', 'python-async'],
|
||||
['Pytest', 'pytest'],
|
||||
['C#', 'csharp'],
|
||||
['C# NUnit', 'csharp-nunit'],
|
||||
['C# MSTest', 'csharp-mstest'],
|
||||
['Playwright Test', 'test'],
|
||||
]);
|
||||
const codegenLangId2lang = new Map([...codegenLang2Id.entries()].map(([lang, langId]) => [langId, lang]));
|
||||
|
|
Загрузка…
Ссылка в новой задаче