feat(codegen): add NUnit/MSTest (#16803)

This commit is contained in:
Max Schmitt 2022-08-25 11:58:58 +02:00 коммит произвёл GitHub
Родитель 2c1723b6f5
Коммит 74ab343e2b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 152 добавлений и 12 удалений

Просмотреть файл

@ -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]));