docs: linkify params and options (#32823)
References https://github.com/microsoft/playwright/issues/32590.
This commit is contained in:
Родитель
a9d5c39d40
Коммит
a2bdb2fd79
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -94,18 +94,20 @@ export interface FullResult {
|
||||||
*
|
*
|
||||||
* Here is a typical order of reporter calls:
|
* Here is a typical order of reporter calls:
|
||||||
* - [reporter.onBegin(config, suite)](https://playwright.dev/docs/api/class-reporter#reporter-on-begin) is called
|
* - [reporter.onBegin(config, suite)](https://playwright.dev/docs/api/class-reporter#reporter-on-begin) is called
|
||||||
* once with a root suite that contains all other suites and tests. Learn more about [suites hierarchy]{@link
|
* once with a root suite that contains all other suites and tests. Learn more about
|
||||||
* Suite}.
|
* [suites hierarchy][Suite](https://playwright.dev/docs/api/class-suite).
|
||||||
* - [reporter.onTestBegin(test, result)](https://playwright.dev/docs/api/class-reporter#reporter-on-test-begin) is
|
* - [reporter.onTestBegin(test, result)](https://playwright.dev/docs/api/class-reporter#reporter-on-test-begin) is
|
||||||
* called for each test run. It is given a {@link TestCase} that is executed, and a {@link TestResult} that is
|
* called for each test run. It is given a [TestCase](https://playwright.dev/docs/api/class-testcase) that is
|
||||||
* almost empty. Test result will be populated while the test runs (for example, with steps and stdio) and will
|
* executed, and a [TestResult](https://playwright.dev/docs/api/class-testresult) that is almost empty. Test
|
||||||
* get final `status` once the test finishes.
|
* result will be populated while the test runs (for example, with steps and stdio) and will get final `status`
|
||||||
|
* once the test finishes.
|
||||||
* - [reporter.onStepBegin(test, result, step)](https://playwright.dev/docs/api/class-reporter#reporter-on-step-begin)
|
* - [reporter.onStepBegin(test, result, step)](https://playwright.dev/docs/api/class-reporter#reporter-on-step-begin)
|
||||||
* and
|
* and
|
||||||
* [reporter.onStepEnd(test, result, step)](https://playwright.dev/docs/api/class-reporter#reporter-on-step-end)
|
* [reporter.onStepEnd(test, result, step)](https://playwright.dev/docs/api/class-reporter#reporter-on-step-end)
|
||||||
* are called for each executed step inside the test. When steps are executed, test run has not finished yet.
|
* are called for each executed step inside the test. When steps are executed, test run has not finished yet.
|
||||||
* - [reporter.onTestEnd(test, result)](https://playwright.dev/docs/api/class-reporter#reporter-on-test-end) is
|
* - [reporter.onTestEnd(test, result)](https://playwright.dev/docs/api/class-reporter#reporter-on-test-end) is
|
||||||
* called when test run has finished. By this time, {@link TestResult} is complete and you can use
|
* called when test run has finished. By this time, [TestResult](https://playwright.dev/docs/api/class-testresult)
|
||||||
|
* is complete and you can use
|
||||||
* [testResult.status](https://playwright.dev/docs/api/class-testresult#test-result-status),
|
* [testResult.status](https://playwright.dev/docs/api/class-testresult#test-result-status),
|
||||||
* [testResult.error](https://playwright.dev/docs/api/class-testresult#test-result-error) and more.
|
* [testResult.error](https://playwright.dev/docs/api/class-testresult#test-result-error) and more.
|
||||||
* - [reporter.onEnd(result)](https://playwright.dev/docs/api/class-reporter#reporter-on-end) is called once after
|
* - [reporter.onEnd(result)](https://playwright.dev/docs/api/class-reporter#reporter-on-end) is called once after
|
||||||
|
@ -128,12 +130,13 @@ export interface FullResult {
|
||||||
* **Merged report API notes**
|
* **Merged report API notes**
|
||||||
*
|
*
|
||||||
* When merging multiple [`blob`](https://playwright.dev/docs/test-reporters#blob-reporter) reports via
|
* When merging multiple [`blob`](https://playwright.dev/docs/test-reporters#blob-reporter) reports via
|
||||||
* [`merge-reports`](https://playwright.dev/docs/test-sharding#merge-reports-cli) CLI command, the same {@link Reporter} API is called to
|
* [`merge-reports`](https://playwright.dev/docs/test-sharding#merge-reports-cli) CLI command, the same
|
||||||
* produce final reports and all existing reporters should work without any changes. There some subtle differences
|
* [Reporter](https://playwright.dev/docs/api/class-reporter) API is called to produce final reports and all existing
|
||||||
* though which might affect some custom reporters.
|
* reporters should work without any changes. There some subtle differences though which might affect some custom
|
||||||
* - Projects from different shards are always kept as separate {@link TestProject} objects. E.g. if project
|
* reporters.
|
||||||
* 'Desktop Chrome' was sharded across 5 machines then there will be 5 instances of projects with the same name in
|
* - Projects from different shards are always kept as separate
|
||||||
* the config passed to
|
* [TestProject](https://playwright.dev/docs/api/class-testproject) objects. E.g. if project 'Desktop Chrome' was
|
||||||
|
* sharded across 5 machines then there will be 5 instances of projects with the same name in the config passed to
|
||||||
* [reporter.onBegin(config, suite)](https://playwright.dev/docs/api/class-reporter#reporter-on-begin).
|
* [reporter.onBegin(config, suite)](https://playwright.dev/docs/api/class-reporter#reporter-on-begin).
|
||||||
*/
|
*/
|
||||||
export interface Reporter {
|
export interface Reporter {
|
||||||
|
@ -151,8 +154,8 @@ export interface Reporter {
|
||||||
*/
|
*/
|
||||||
onEnd?(result: FullResult): Promise<{ status?: FullResult['status'] } | undefined | void> | void;
|
onEnd?(result: FullResult): Promise<{ status?: FullResult['status'] } | undefined | void> | void;
|
||||||
/**
|
/**
|
||||||
* Called once before running tests. All tests have been already discovered and put into a hierarchy of {@link
|
* Called once before running tests. All tests have been already discovered and put into a hierarchy of
|
||||||
* Suite}s.
|
* [Suite](https://playwright.dev/docs/api/class-suite)s.
|
||||||
* @param config Resolved configuration.
|
* @param config Resolved configuration.
|
||||||
* @param suite The root suite that contains all projects, files and test cases.
|
* @param suite The root suite that contains all projects, files and test cases.
|
||||||
*/
|
*/
|
||||||
|
@ -321,16 +324,16 @@ export {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `Suite` is a group of tests. All tests in Playwright Test form the following hierarchy:
|
* `Suite` is a group of tests. All tests in Playwright Test form the following hierarchy:
|
||||||
* - Root suite has a child suite for each {@link FullProject}.
|
* - Root suite has a child suite for each [FullProject](https://playwright.dev/docs/api/class-fullproject).
|
||||||
* - Project suite #1. Has a child suite for each test file in the project.
|
* - Project suite #1. Has a child suite for each test file in the project.
|
||||||
* - File suite #1
|
* - File suite #1
|
||||||
* - {@link TestCase} #1
|
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #1
|
||||||
* - {@link TestCase} #2
|
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #2
|
||||||
* - Suite corresponding to a
|
* - Suite corresponding to a
|
||||||
* [test.describe([title, details, callback])](https://playwright.dev/docs/api/class-test#test-describe)
|
* [test.describe([title, details, callback])](https://playwright.dev/docs/api/class-test#test-describe)
|
||||||
* group
|
* group
|
||||||
* - {@link TestCase} #1 in a group
|
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #1 in a group
|
||||||
* - {@link TestCase} #2 in a group
|
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #2 in a group
|
||||||
* - < more test cases ... >
|
* - < more test cases ... >
|
||||||
* - File suite #2
|
* - File suite #2
|
||||||
* - < more file suites ... >
|
* - < more file suites ... >
|
||||||
|
@ -376,7 +379,7 @@ export interface Suite {
|
||||||
parent?: Suite;
|
parent?: Suite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Child suites. See {@link Suite} for the hierarchy of suites.
|
* Child suites. See [Suite](https://playwright.dev/docs/api/class-suite) for the hierarchy of suites.
|
||||||
*/
|
*/
|
||||||
suites: Array<Suite>;
|
suites: Array<Suite>;
|
||||||
|
|
||||||
|
@ -578,7 +581,7 @@ export interface TestError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A result of a single {@link TestCase} run.
|
* A result of a single [TestCase](https://playwright.dev/docs/api/class-testcase) run.
|
||||||
*/
|
*/
|
||||||
export interface TestResult {
|
export interface TestResult {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -45,9 +45,8 @@ const md = require('../markdown');
|
||||||
* @typedef {function({
|
* @typedef {function({
|
||||||
* clazz?: Class,
|
* clazz?: Class,
|
||||||
* member?: Member,
|
* member?: Member,
|
||||||
* param?: string,
|
* param?: { name: string, alias: string },
|
||||||
* option?: string,
|
* option?: { name: string, alias: string },
|
||||||
* optionFullPath?: string,
|
|
||||||
* href?: string,
|
* href?: string,
|
||||||
* }): string|undefined} Renderer
|
* }): string|undefined} Renderer
|
||||||
*/
|
*/
|
||||||
|
@ -742,7 +741,7 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
|
||||||
return linkRenderer({ member, href }) || match;
|
return linkRenderer({ member, href }) || match;
|
||||||
}
|
}
|
||||||
if (p1 === 'param' || p1 === 'option') {
|
if (p1 === 'param' || p1 === 'option') {
|
||||||
let /** @type {string } */ alias;
|
let /** @type {string } */ name;
|
||||||
let /** @type {Member} */ member;
|
let /** @type {Member} */ member;
|
||||||
if (p2.includes('.')) {
|
if (p2.includes('.')) {
|
||||||
// fully-qualified name
|
// fully-qualified name
|
||||||
|
@ -751,7 +750,7 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
|
||||||
if (!maybeMember)
|
if (!maybeMember)
|
||||||
throw new Error(`Undefined reference: ${match}\n=========\n${text}`);
|
throw new Error(`Undefined reference: ${match}\n=========\n${text}`);
|
||||||
member = maybeMember;
|
member = maybeMember;
|
||||||
alias = rest.join('.');
|
name = rest.join('.');
|
||||||
} else {
|
} else {
|
||||||
// non-fully-qualified param/option reference from the same method.
|
// non-fully-qualified param/option reference from the same method.
|
||||||
if (!classOrMember || !(classOrMember instanceof Member)) {
|
if (!classOrMember || !(classOrMember instanceof Member)) {
|
||||||
|
@ -762,23 +761,23 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
|
||||||
if (!maybeMember)
|
if (!maybeMember)
|
||||||
throw new Error(`Undefined reference: ${match}\n=========\n${text}`);
|
throw new Error(`Undefined reference: ${match}\n=========\n${text}`);
|
||||||
member = maybeMember;
|
member = maybeMember;
|
||||||
alias = p2;
|
name = p2;
|
||||||
}
|
}
|
||||||
if (p1 === 'param') {
|
if (p1 === 'param') {
|
||||||
const param = member.argsArray.find(a => a.name === alias);
|
const param = member.argsArray.find(a => a.name === name);
|
||||||
if (!param)
|
if (!param)
|
||||||
throw new Error(`Referenced parameter ${match} not found in the parent method ${member.name}\n=========\n${text}`);
|
throw new Error(`Referenced parameter ${match} not found in the parent method ${member.name}\n=========\n${text}`);
|
||||||
alias = param.alias;
|
return linkRenderer({ member, param: { name, alias: param.alias }, href }) || match;
|
||||||
return linkRenderer({ member, param: alias, href }) || match;
|
|
||||||
} else {
|
} else {
|
||||||
// p1 === 'option'
|
// p1 === 'option'
|
||||||
const options = member.argsArray.find(a => a.name === 'options');
|
const options = member.argsArray.find(a => a.name === 'options');
|
||||||
const parts = alias.split('.');
|
const parts = name.split('.');
|
||||||
const option = options?.type?.properties?.find(a => a.name === parts[0]);
|
const optionName = parts[0];
|
||||||
|
const option = options?.type?.properties?.find(a => a.name === optionName);
|
||||||
if (!option)
|
if (!option)
|
||||||
throw new Error(`Referenced option ${match} not found in the parent method ${member.name}\n=========\n${text}`);
|
throw new Error(`Referenced option ${match} not found in the parent method ${member.name}\n=========\n${text}`);
|
||||||
parts[0] = option.alias;
|
parts[0] = option.alias;
|
||||||
return linkRenderer({ member, option: parts[0], optionFullPath: parts.join('.'), href }) || match;
|
return linkRenderer({ member, option: { name: optionName, alias: parts.join('.') }, href }) || match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error(`Undefined link prefix, expected event|method|property|param|option, got: ` + match);
|
throw new Error(`Undefined link prefix, expected event|method|property|param|option, got: ` + match);
|
||||||
|
|
|
@ -25,9 +25,9 @@ const PROJECT_DIR = path.join(__dirname, '..', '..');
|
||||||
documentation.setLinkRenderer(item => {
|
documentation.setLinkRenderer(item => {
|
||||||
const { clazz, param, option } = item;
|
const { clazz, param, option } = item;
|
||||||
if (param)
|
if (param)
|
||||||
return `\`${param}\``;
|
return `\`${param.alias}\``;
|
||||||
if (option)
|
if (option)
|
||||||
return `\`${option}\``;
|
return `\`${option.alias}\``;
|
||||||
if (clazz)
|
if (clazz)
|
||||||
return `\`${clazz.name}\``;
|
return `\`${clazz.name}\``;
|
||||||
});
|
});
|
||||||
|
|
|
@ -61,9 +61,9 @@ documentation.setLinkRenderer(item => {
|
||||||
else if (item.member)
|
else if (item.member)
|
||||||
return `<see cref="I${toTitleCase(item.member.clazz.name)}.${toMemberName(item.member)}${asyncSuffix}"/>`;
|
return `<see cref="I${toTitleCase(item.member.clazz.name)}.${toMemberName(item.member)}${asyncSuffix}"/>`;
|
||||||
else if (item.option)
|
else if (item.option)
|
||||||
return `<paramref name="${item.option}"/>`;
|
return `<paramref name="${item.option.name}"/>`;
|
||||||
else if (item.param)
|
else if (item.param)
|
||||||
return `<paramref name="${item.param}"/>`;
|
return `<paramref name="${item.param.name}"/>`;
|
||||||
else
|
else
|
||||||
throw new Error('Unknown link format.');
|
throw new Error('Unknown link format.');
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,7 +20,16 @@
|
||||||
const toKebabCase = require('lodash/kebabCase.js')
|
const toKebabCase = require('lodash/kebabCase.js')
|
||||||
const Documentation = require('./documentation');
|
const Documentation = require('./documentation');
|
||||||
|
|
||||||
function createMarkdownLink(languagePath, member, text) {
|
/**
|
||||||
|
* @param {string} languagePath
|
||||||
|
* @param {Documentation.Member} member
|
||||||
|
* @param {string} text
|
||||||
|
* @param {string=} paramOrOption
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function createMarkdownLink(languagePath, member, text, paramOrOption) {
|
||||||
|
if (!member.clazz)
|
||||||
|
throw new Error('Member without a class!');
|
||||||
const className = toKebabCase(member.clazz.name);
|
const className = toKebabCase(member.clazz.name);
|
||||||
const memberName = toKebabCase(member.name);
|
const memberName = toKebabCase(member.name);
|
||||||
let hash = null;
|
let hash = null;
|
||||||
|
@ -28,6 +37,8 @@ function createMarkdownLink(languagePath, member, text) {
|
||||||
hash = `${className}-${memberName}`.toLowerCase();
|
hash = `${className}-${memberName}`.toLowerCase();
|
||||||
else if (member.kind === 'event')
|
else if (member.kind === 'event')
|
||||||
hash = `${className}-event-${memberName}`.toLowerCase();
|
hash = `${className}-event-${memberName}`.toLowerCase();
|
||||||
|
if (paramOrOption)
|
||||||
|
hash += '-option-' + toKebabCase(paramOrOption).toLowerCase();
|
||||||
return `[${text}](https://playwright.dev${languagePath}/docs/api/class-${member.clazz.name.toLowerCase()}#${hash})`;
|
return `[${text}](https://playwright.dev${languagePath}/docs/api/class-${member.clazz.name.toLowerCase()}#${hash})`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,26 +52,21 @@ function createClassMarkdownLink(languagePath, clazz) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} language
|
* @param {string} language
|
||||||
* @param {OutputType} outputType
|
* @param {OutputType} outputType
|
||||||
* @returns {Documentation.Renderer}
|
* @returns {Documentation.Renderer}
|
||||||
*/
|
*/
|
||||||
function docsLinkRendererForLanguage(language, outputType) {
|
function docsLinkRendererForLanguage(language, outputType) {
|
||||||
const languagePath = languageToRelativeDocsPath(language);
|
const languagePath = languageToRelativeDocsPath(language);
|
||||||
return ({ clazz, member, param, option }) => {
|
return ({ clazz, member, param, option }) => {
|
||||||
if (param)
|
if (clazz)
|
||||||
return `\`${param}\``;
|
return createClassMarkdownLink(languagePath, clazz);
|
||||||
if (option)
|
|
||||||
return `\`${option}\``;
|
|
||||||
if (clazz) {
|
|
||||||
if (outputType === 'Types')
|
|
||||||
return `{@link ${clazz.name}}`;
|
|
||||||
if (outputType === 'ReleaseNotesMd')
|
|
||||||
return createClassMarkdownLink(languagePath, clazz);
|
|
||||||
throw new Error(`Unexpected output type ${outputType}`);
|
|
||||||
}
|
|
||||||
if (!member || !member.clazz)
|
if (!member || !member.clazz)
|
||||||
throw new Error('Internal error');
|
throw new Error('Internal error');
|
||||||
|
if (param)
|
||||||
|
return createMarkdownLink(languagePath, member, `\`${param.alias}\``, param.name);
|
||||||
|
if (option)
|
||||||
|
return createMarkdownLink(languagePath, member, `\`${option.alias}\``, option.name);
|
||||||
const className = member.clazz.varName === 'playwrightAssertions' ? '' : member.clazz.varName + '.';
|
const className = member.clazz.varName === 'playwrightAssertions' ? '' : member.clazz.varName + '.';
|
||||||
if (member.kind === 'method') {
|
if (member.kind === 'method') {
|
||||||
const args = outputType === 'ReleaseNotesMd' ? '' : renderJSSignature(member.argsArray);
|
const args = outputType === 'ReleaseNotesMd' ? '' : renderJSSignature(member.argsArray);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче