chore: generate more types (#13358)

As a result, fix documentation issues:
- Removed `TestStep.data` that is not a thing.
- Added `TestConfig.name` documentation.
- Refined a lot of optional types in the documentation.
- Aligned `test.fail()` and `test.slow()` docs with `test.skip()`.
- Strict set of docs vs types inconsistensies in the generator
This commit is contained in:
Dmitry Gozman 2022-04-06 13:36:20 -07:00 committed by GitHub
parent d9d826b7f6
commit 4123a55be5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 794 additions and 1067 deletions

View File

@ -9,9 +9,9 @@ title: "Annotations"
Playwright Test supports test annotations to deal with failures, flakiness, skip, focus and tag tests:
- [`method: Test.skip#1`] marks the test as irrelevant. Playwright Test does not run such a test. Use this annotation when the test is not applicable in some configuration.
- [`method: Test.fail`] marks the test as failing. Playwright Test will run this test and ensure it does indeed fail. If the test does not fail, Playwright Test will complain.
- [`method: Test.fail#1`] marks the test as failing. Playwright Test will run this test and ensure it does indeed fail. If the test does not fail, Playwright Test will complain.
- [`method: Test.fixme#1`] marks the test as failing. Playwright Test will not run this test, as opposite to the `fail` annotation. Use `fixme` when running the test is slow or crashy.
- [`method: Test.slow`] marks the test as slow and triples the test timeout.
- [`method: Test.slow#1`] marks the test as slow and triples the test timeout.
Annotations can be used on a single test or a group of tests. Annotations can be conditional, in which case they apply when the condition is truthy. Annotations may depend on test fixtures. There could be multiple annotations on the same test, possibly in different configurations.

View File

@ -630,11 +630,9 @@ An object containing fixtures and/or options. Learn more about [fixtures format]
## method: Test.fail
## method: Test.fail#1
Marks a test or a group of tests as "should fail". Playwright Test runs these tests and ensures that they are actually failing. This is useful for documentation purposes to acknowledge that some functionality is broken until it is fixed.
Unconditional fail:
Unconditonally marks a test as "should fail". Playwright Test runs this test and ensures that it is actually failing. This is useful for documentation purposes to acknowledge that some functionality is broken until it is fixed.
```js js-flavor=js
const { test, expect } = require('@playwright/test');
@ -654,7 +652,9 @@ test('not yet ready', async ({ page }) => {
});
```
Conditional fail a test with an optional description:
## method: Test.fail#2
Conditionally mark a test as "should fail" with an optional description.
```js js-flavor=js
const { test, expect } = require('@playwright/test');
@ -674,45 +674,56 @@ test('fail in WebKit', async ({ page, browserName }) => {
});
```
Conditional fail for all tests in a file or [`method: Test.describe`] group:
### param: Test.fail#2.condition
- `condition` <[boolean]>
```js js-flavor=js
const { test, expect } = require('@playwright/test');
Test is marked as "should fail" when the condition is `true`.
test.fail(({ browserName }) => browserName === 'webkit');
test('fail in WebKit 1', async ({ page }) => {
// ...
});
test('fail in WebKit 2', async ({ page }) => {
// ...
});
```
```js js-flavor=ts
import { test, expect } from '@playwright/test';
test.fail(({ browserName }) => browserName === 'webkit');
test('fail in WebKit 1', async ({ page }) => {
// ...
});
test('fail in WebKit 2', async ({ page }) => {
// ...
});
```
### param: Test.fail.condition
- `condition` <[void]|[boolean]|[function]\([Fixtures]\):[boolean]>
Optional condition - either a boolean value, or a function that takes a fixtures object and returns a boolean. Test or tests are marked as "should fail" when the condition is `true`.
### param: Test.fail.description
- `description` <[void]|[string]>
### param: Test.fail#2.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## method: Test.fail#3
Conditionally mark all tests in a file or [`method: Test.describe`] group as "should fail".
```js js-flavor=js
const { test, expect } = require('@playwright/test');
test.fail(({ browserName }) => browserName === 'webkit');
test('fail in WebKit 1', async ({ page }) => {
// ...
});
test('fail in WebKit 2', async ({ page }) => {
// ...
});
```
```js js-flavor=ts
import { test, expect } from '@playwright/test';
test.fail(({ browserName }) => browserName === 'webkit');
test('fail in WebKit 1', async ({ page }) => {
// ...
});
test('fail in WebKit 2', async ({ page }) => {
// ...
});
```
### param: Test.fail#3.condition
- `callback` <[function]\([Fixtures]\):[boolean]>
A function that returns whether to mark as "should fail", based on test fixtures. Test or tests are marked as "should fail" when the return value is `true`.
### param: Test.fail#3.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## method: Test.fixme#1
@ -824,12 +835,12 @@ test('broken in WebKit', async ({ page, browserName }) => {
### param: Test.fixme#3.condition
- `condition` <[boolean]>
Test or tests are marked as "fixme" when the condition is `true`.
Test is marked as "fixme" when the condition is `true`.
### param: Test.fixme#3.description
- `description` <[void]|[string]>
- `description` <[string]>
An optional description that will be reflected in a test report.
Optional description that will be reflected in a test report.
@ -871,9 +882,9 @@ test('broken in WebKit 2', async ({ page }) => {
A function that returns whether to mark as "fixme", based on test fixtures. Test or tests are marked as "fixme" when the return value is `true`.
### param: Test.fixme#4.description
- `description` <[void]|[string]>
- `description` <[string]>
An optional description that will be reflected in a test report.
Optional description that will be reflected in a test report.
## method: Test.info
@ -1089,12 +1100,12 @@ test.beforeEach(async ({ page }) => {
### param: Test.skip#3.condition
- `condition` <[boolean]>
A skip condition. Test or tests are skipped when the condition is `true`.
A skip condition. Test is skipped when the condition is `true`.
### param: Test.skip#3.description
- `description` <[void]|[string]>
An optional description that will be reflected in a test report.
Optional description that will be reflected in a test report.
@ -1136,17 +1147,15 @@ test('skip in WebKit 2', async ({ page }) => {
A function that returns whether to skip, based on test fixtures. Test or tests are skipped when the return value is `true`.
### param: Test.skip#4.description
- `description` <[void]|[string]>
- `description` <[string]>
An optional description that will be reflected in a test report.
Optional description that will be reflected in a test report.
## method: Test.slow
## method: Test.slow#1
Marks a test or a group of tests as "slow". Slow tests will be given triple the default timeout.
Unconditional slow:
Unconditionally marks a test as "slow". Slow test will be given triple the default timeout.
```js js-flavor=js
const { test, expect } = require('@playwright/test');
@ -1166,7 +1175,9 @@ test('slow test', async ({ page }) => {
});
```
Conditional slow a test with an optional description:
## method: Test.slow#2
Conditionally mark a test as "slow" with an optional description. Slow test will be given triple the default timeout.
```js js-flavor=js
const { test, expect } = require('@playwright/test');
@ -1186,7 +1197,20 @@ test('slow in WebKit', async ({ page, browserName }) => {
});
```
Conditional slow for all tests in a file or [`method: Test.describe`] group:
### param: Test.slow#2.condition
- `condition` <[boolean]>
Test is marked as "slow" when the condition is `true`.
### param: Test.slow#2.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## method: Test.slow#3
Conditionally mark all tests in a file or [`method: Test.describe`] group as "slow". Slow tests will be given triple the default timeout.
```js js-flavor=js
const { test, expect } = require('@playwright/test');
@ -1214,13 +1238,13 @@ test('fail in WebKit 2', async ({ page }) => {
});
```
### param: Test.slow.condition
- `condition` <[void]|[boolean]|[function]\([Fixtures]\):[boolean]>
### param: Test.slow#3.condition
- `callback` <[function]\([Fixtures]\):[boolean]>
Optional condition - either a boolean value, or a function that takes a fixtures object and returns a boolean. Test or tests are marked as "slow" when the condition is `true`.
A function that returns whether to mark as "slow", based on test fixtures. Test or tests are marked as "slow" when the return value is `true`.
### param: Test.slow.description
- `description` <[void]|[string]>
### param: Test.slow#3.description
- `description` <[string]>
Optional description that will be reflected in a test report.

View File

@ -245,6 +245,11 @@ export default config;
Any JSON-serializable metadata that will be put directly to the test report.
## property: TestConfig.name
- type: <[string]>
Config name is visible in the report and during test execution, unless overridden by [`property: TestProject.name`].
## property: TestConfig.outputDir
- type: <[string]>

View File

@ -4,16 +4,16 @@
Information about an error thrown during test execution.
## property: TestError.message
- type: <[void]|[string]>
- type: <[string]>
Error message. Set when [Error] (or its subclass) has been thrown.
Optional error message. Set when [Error] (or its subclass) has been thrown.
## property: TestError.stack
- type: <[void]|[string]>
- type: <[string]>
Error stack. Set when [Error] (or its subclass) has been thrown.
Optional error stack. Set when [Error] (or its subclass) has been thrown.
## property: TestError.value
- type: <[void]|[string]>
- type: <[string]>
The value that was thrown. Set when anything except the [Error] (or its subclass) has been thrown.
Optional value that was thrown. Set when anything except the [Error] (or its subclass) has been thrown.

View File

@ -25,7 +25,7 @@ test('basic test', async ({ page }, testInfo) => {
## property: TestInfo.annotations
- type: <[Array]<[Object]>>
- `type` <[string]> Annotation type, for example `'skip'` or `'fail'`.
- `description` <[void]|[string]> Optional description.
- `description` <[string]> Optional description.
The list of annotations applicable to the current test. Includes annotations from the test, annotations from all [`method: Test.describe`] groups the test belongs to and file-level annotations for the test file.
@ -35,8 +35,8 @@ Learn more about [test annotations](../test-annotations.md).
- type: <[Array]<[Object]>>
- `name` <[string]> Attachment name.
- `contentType` <[string]> Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`.
- `path` <[void]|[string]> Optional path on the filesystem to the attached file.
- `body` <[void]|[Buffer]> Optional attachment body used instead of a file.
- `path` <[string]> Optional path on the filesystem to the attached file.
- `body` <[Buffer]> Optional attachment body used instead of a file.
The list of files or buffers attached to the current test. Some reporters show test attachments.
@ -103,7 +103,7 @@ after awaiting the attach call.
- `body` <[string]|[Buffer]> Attachment body. Mutually exclusive with [`option: path`].
### option: TestInfo.attach.contentType
- `contentType` <[void]|[string]> Optional content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`. If omitted, content type is inferred based on the [`option: path`], or defaults to `text/plain` for [string] attachments and `application/octet-stream` for [Buffer] attachments.
- `contentType` <[string]> Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`. If omitted, content type is inferred based on the [`option: path`], or defaults to `text/plain` for [string] attachments and `application/octet-stream` for [Buffer] attachments.
### option: TestInfo.attach.path
- `path` <[string]> Path on the filesystem to the attached file. Mutually exclusive with [`option: body`].
@ -128,9 +128,9 @@ The number of milliseconds the test took to finish. Always zero before the test
## property: TestInfo.error
- type: <[void]|[TestError]>
- type: <[TestError]>
First error thrown during test execution, if any. This is equal to the first
Optional first error thrown during test execution, if any. This is equal to the first
element in [`property: TestInfo.errors`].
## property: TestInfo.errors
@ -144,7 +144,7 @@ Errors thrown during test execution, if any.
Expected status for the currently running test. This is usually `'passed'`, except for a few cases:
* `'skipped'` for skipped tests, e.g. with [`method: Test.skip#2`];
* `'failed'` for tests marked as failed with [`method: Test.fail`].
* `'failed'` for tests marked as failed with [`method: Test.fail#1`].
Expected status is usually compared with the actual [`property: TestInfo.status`]:
@ -166,41 +166,52 @@ test.afterEach(async ({}, testInfo) => {
});
```
## method: TestInfo.fail
## method: TestInfo.fail#1
Marks the currently running test as "should fail". Playwright Test ensures that this test is actually failing. This is similar to [`method: Test.fail`].
Marks the currently running test as "should fail". Playwright Test runs theis tests and ensures that it is actually failing. This is useful for documentation purposes to acknowledge that some functionality is broken until it is fixed. This is similar to [`method: Test.fail#1`].
### param: TestInfo.fail.condition
- `condition` <[void]|[boolean]>
## method: TestInfo.fail#2
Optional condition - the test is marked as "should fail" when the condition is `true`.
Conditionally mark the currently running test as "should fail" with an optional description. This is similar to [`method: Test.fail#2`].
### param: TestInfo.fail.description
- `description` <[void]|[string]>
### param: TestInfo.fail#2.condition
- `condition` <[boolean]>
Test is marked as "should fail" when the condition is `true`.
### param: TestInfo.fail#2.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## property: TestInfo.file
- type: <[string]>
Absolute path to a file where the currently running test is declared.
## method: TestInfo.fixme
Marks the currently running test as "fixme". The test will be skipped, but the intention is to fix it. This is similar to [`method: Test.fixme#2`].
## method: TestInfo.fixme#1
### param: TestInfo.fixme.condition
- `condition` <[void]|[boolean]>
Mark a test as "fixme", with the intention to fix it. Test is immediately aborted. This is similar to [`method: Test.fixme#2`].
Optional condition - the test is marked as "fixme" when the condition is `true`.
## method: TestInfo.fixme#2
### param: TestInfo.fixme.description
- `description` <[void]|[string]>
Conditionally mark the currently running test as "fixme" with an optional description. This is similar to [`method: Test.fixme#3`].
### param: TestInfo.fixme#2.condition
- `condition` <[boolean]>
Test is marked as "fixme" when the condition is `true`.
### param: TestInfo.fixme#2.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## property: TestInfo.fn
- type: <[function]\([TestArgs], [TestInfo]\)>
- type: <[function]>
Test function as passed to `test(title, testFunction)`.
@ -248,7 +259,7 @@ test('example test', async ({}, testInfo) => {
> However, this path must stay within the [`property: TestInfo.outputDir`] directory for each test (i.e. `test-results/a-test-title`), otherwise it will throw.
### param: TestInfo.outputPath.pathSegments
- `pathSegments` <[string...]>
- `...pathSegments` <[Array]<[string]>>
Path segments to append at the end of the resulting path.
@ -338,34 +349,44 @@ test.beforeEach(async ({ page }, testInfo) => {
Timeout in milliseconds.
## method: TestInfo.skip
## method: TestInfo.skip#1
Skips the currently running test. This is similar to [`method: Test.skip#2`].
Unconditionally skip the currently running test. Test is immediately aborted. This is similar to [`method: Test.skip#2`].
### param: TestInfo.skip.condition
- `condition` <[void]|[boolean]>
## method: TestInfo.skip#2
Optional condition - the test is skipped when the condition is `true`.
Conditionally skips the currently running test with an optional description. This is similar to [`method: Test.skip#3`].
### param: TestInfo.skip.description
- `description` <[void]|[string]>
### param: TestInfo.skip#2.condition
- `condition` <[boolean]>
A skip condition. Test is skipped when the condition is `true`.
### param: TestInfo.skip#2.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## method: TestInfo.slow
Marks the currently running test as "slow", giving it triple the default timeout. This is similar to [`method: Test.slow`].
## method: TestInfo.slow#1
### param: TestInfo.slow.condition
- `condition` <[void]|[boolean]>
Marks the currently running test as "slow", giving it triple the default timeout. This is similar to [`method: Test.slow#1`].
Optional condition - the test is marked as "slow" when the condition is `true`.
## method: TestInfo.slow#2
### param: TestInfo.slow.description
- `description` <[void]|[string]>
Conditionally mark the currently running test as "slow" with an optional description, giving it triple the default timeout. This is similar to [`method: Test.slow#2`].
### param: TestInfo.slow#2.condition
- `condition` <[boolean]>
Test is marked as "slow" when the condition is `true`.
### param: TestInfo.slow#2.description
- `description` <[string]>
Optional description that will be reflected in a test report.
## method: TestInfo.snapshotPath
- returns: <[string]>
@ -375,7 +396,7 @@ Returns a path to a snapshot file with the given `pathSegments`. Learn more abou
> However, this path must stay within the snapshots directory for each test file (i.e. `a.spec.js-snapshots`), otherwise it will throw.
### param: TestInfo.snapshotPath.pathSegments
- `pathSegments` <[string...]>
- `...pathSegments` <[Array]<[string]>>
The name of the snapshot or the path segments to define the snapshot file path. Snapshots with the same name in the same test file are expected to be the same.

View File

@ -25,14 +25,14 @@ Reporter is given a root suite in the [`method: Reporter.onBegin`] method.
Returns the list of all test cases in this suite and its descendants, as opposite to [`property: Suite.tests`].
## property: Suite.location
- type: <[void]|[Location]>
- type: <[Location]>
Location in the source where the suite is defined. Missing for root and project suites.
Optional location in the source where the suite is defined. Missing for root and project suites.
## property: Suite.parent
- type: <[void]|[Suite]>
- type: <[Suite]>
Parent suite or [void] for the root suite.
Optional parent suite, missing for the root suite.
## method: Suite.project
- returns: <[void]|[TestProject]>

View File

@ -6,7 +6,7 @@
## property: TestCase.annotations
- type: <[Array]<[Object]>>
- `type` <[string]> Annotation type, for example `'skip'` or `'fail'`.
- `description` <[void]|[string]> Optional description.
- `description` <[string]> Optional description.
The list of annotations applicable to the current test. Includes annotations from the test, annotations from all [`method: Test.describe`] groups the test belongs to and file-level annotations for the test file.
@ -19,13 +19,13 @@ Learn more about [test annotations](../test-annotations.md).
Expected test status.
* Tests marked as [`method: Test.skip#1`] or [`method: Test.fixme#1`] are expected to be `'skipped'`.
* Tests marked as [`method: Test.fail`] are expected to be `'failed'`.
* Tests marked as [`method: Test.fail#1`] are expected to be `'failed'`.
* Other tests are expected to be `'passed'`.
See also [`property: TestResult.status`] for the actual status.
## property: TestCase.location
- type: <[void]|[Location]>
- type: <[Location]>
Location in the source where the test is defined.
@ -66,7 +66,7 @@ Learn more about [test retries](../test-retries.md#retries).
## property: TestCase.timeout
- type: <[float]>
The timeout given to the test. Affected by [`property: TestConfig.timeout`], [`property: TestProject.timeout`], [`method: Test.setTimeout`], [`method: Test.slow`] and [`method: TestInfo.setTimeout`].
The timeout given to the test. Affected by [`property: TestConfig.timeout`], [`property: TestProject.timeout`], [`method: Test.setTimeout`], [`method: Test.slow#1`] and [`method: TestInfo.setTimeout`].
## property: TestCase.title
- type: <[string]>

View File

@ -7,8 +7,8 @@ A result of a single [TestCase] run.
- type: <[Array]<[Object]>>
- `name` <[string]> Attachment name.
- `contentType` <[string]> Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`.
- `path` <[void]|[string]> Optional path on the filesystem to the attached file.
- `body` <[void]|[Buffer]> Optional attachment body used instead of a file.
- `path` <[string]> Optional path on the filesystem to the attached file.
- `body` <[Buffer]> Optional attachment body used instead of a file.
The list of files or buffers attached during the test execution through [`property: TestInfo.attachments`].
@ -18,9 +18,9 @@ The list of files or buffers attached during the test execution through [`proper
Running time in milliseconds.
## property: TestResult.error
- type: <[void]|[TestError]>
- type: <[TestError]>
First error thrown during test execution, if any. This is equal to the first
Optional first error thrown during test execution, if any. This is equal to the first
element in [`property: TestResult.errors`].
## property: TestResult.errors

View File

@ -18,19 +18,19 @@ Step category to differentiate steps with different origin and verbosity. Built-
Running time in milliseconds.
## property: TestStep.location
- type: <[void]|[Location]>
- type: <[Location]>
Location in the source where the step is defined.
Optional location in the source where the step is defined.
## property: TestStep.error
- type: <[void]|[TestError]>
- type: <[TestError]>
An error thrown during the step execution, if any.
Optional error thrown during the step execution, if any.
## property: TestStep.parent
- type: <[void]|[TestStep]>
- type: <[TestStep]>
Parent step, if any.
Optional parent step, if any.
## property: TestStep.startTime
- type: <[Date]>

View File

@ -88,7 +88,7 @@ test('very slow test', async ({ page }) => {
});
```
API reference: [`method: Test.setTimeout`] and [`method: Test.slow`].
API reference: [`method: Test.setTimeout`] and [`method: Test.slow#1`].
### Change timeout from a hook

View File

@ -239,7 +239,6 @@ export class Dispatcher {
duration: -1,
steps: [],
location: params.location,
data: {},
};
steps.set(params.stepId, step);
(parentStep || result).steps.push(step);

File diff suppressed because it is too large Load Diff

View File

@ -18,24 +18,6 @@
import type { FullConfig, FullProject, TestStatus, TestError } from './test';
export type { FullConfig, TestStatus, TestError } from './test';
/**
* Represents a location in the source code where [TestCase] or [Suite] is defined.
*/
export interface Location {
/**
* Path to the source file.
*/
file: string;
/**
* Line number in the source file.
*/
line: number;
/**
* Column number in the source file.
*/
column: number;
}
/**
* `Suite` is a group of tests. All tests in Playwright Test form the following hierarchy:
* - Root suite has a child suite for each [TestProject].
@ -58,9 +40,37 @@ export interface Location {
*/
export interface Suite {
/**
* Parent suite or [void] for the root suite.
* Configuration of the project this suite belongs to, or [void] for the root suite.
*/
project(): FullProject | undefined;
/**
* Returns the list of all test cases in this suite and its descendants, as opposite to
* [suite.tests](https://playwright.dev/docs/api/class-suite#suite-tests).
*/
allTests(): Array<TestCase>;
/**
* Optional location in the source where the suite is defined. Missing for root and project suites.
*/
location?: Location;
/**
* Optional parent suite, missing for the root suite.
*/
parent?: Suite;
/**
* Child suites. See [Suite] for the hierarchy of suites.
*/
suites: Array<Suite>;
/**
* Test cases in the suite. Note that only test cases defined directly in this suite are in the list. Any test cases
* defined in nested [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe) groups are
* listed in the child [suite.suites](https://playwright.dev/docs/api/class-suite#suite-suites).
*/
tests: Array<TestCase>;
/**
* Suite title.
* - Empty for root suite.
@ -70,34 +80,11 @@ export interface Suite {
* group suite.
*/
title: string;
/**
* Location in the source where the suite is defined. Missing for root and project suites.
*/
location?: Location;
/**
* Child suites. See [Suite] for the hierarchy of suites.
*/
suites: Suite[];
/**
* Test cases in the suite. Note that only test cases defined directly in this suite are in the list. Any test cases
* defined in nested [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe) groups are
* listed in the child [suite.suites](https://playwright.dev/docs/api/class-suite#suite-suites).
*/
tests: TestCase[];
/**
* Returns a list of titles from the root down to this suite.
*/
titlePath(): string[];
/**
* Returns the list of all test cases in this suite and its descendants, as opposite to
* [suite.tests](https://playwright.dev/docs/api/class-suite#suite-tests).
*/
allTests(): TestCase[];
/**
* Configuration of the project this suite belongs to, or [void] for the root suite.
*/
project(): FullProject | undefined;
}
titlePath(): Array<string>;}
/**
* `TestCase` corresponds to every [test.(call)(title, testFunction)](https://playwright.dev/docs/api/class-test#test-call)
@ -106,44 +93,17 @@ export interface Suite {
* or repeated multiple times, it will have multiple `TestCase` objects in corresponding projects' suites.
*/
export interface TestCase {
/**
* Suite this test case belongs to.
*/
parent: Suite;
/**
* Test title as passed to the [test.(call)(title, testFunction)](https://playwright.dev/docs/api/class-test#test-call)
* call.
*/
title: string;
/**
* Location in the source where the test is defined.
*/
location: Location;
/**
* Returns a list of titles from the root down to this test.
*/
titlePath(): string[];
/**
* Expected test status.
* - Tests marked as [test.skip(title, testFunction)](https://playwright.dev/docs/api/class-test#test-skip-1) or
* [test.fixme(title, testFunction)](https://playwright.dev/docs/api/class-test#test-fixme-1) are expected to be
* `'skipped'`.
* - Tests marked as [test.fail([condition, description])](https://playwright.dev/docs/api/class-test#test-fail) are
* expected to be `'failed'`.
* - Tests marked as [test.fail()](https://playwright.dev/docs/api/class-test#test-fail-1) are expected to be `'failed'`.
* - Other tests are expected to be `'passed'`.
*
* See also [testResult.status](https://playwright.dev/docs/api/class-testresult#test-result-status) for the actual status.
*/
expectedStatus: TestStatus;
/**
* The timeout given to the test. Affected by
* [testConfig.timeout](https://playwright.dev/docs/api/class-testconfig#test-config-timeout),
* [testProject.timeout](https://playwright.dev/docs/api/class-testproject#test-project-timeout),
* [test.setTimeout(timeout)](https://playwright.dev/docs/api/class-test#test-set-timeout),
* [test.slow([condition, description])](https://playwright.dev/docs/api/class-test#test-slow) and
* [testInfo.setTimeout(timeout)](https://playwright.dev/docs/api/class-testinfo#test-info-set-timeout).
*/
timeout: number;
/**
* The list of annotations applicable to the current test. Includes annotations from the test, annotations from all
* [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe) groups the test belongs to
@ -154,138 +114,164 @@ export interface TestCase {
*
* Learn more about [test annotations](https://playwright.dev/docs/test-annotations).
*/
annotations: { type: string, description?: string }[];
annotations: Array<{
/**
* Annotation type, for example `'skip'` or `'fail'`.
*/
type: string;
/**
* Optional description.
*/
description?: string;
}>;
/**
* The maximum number of retries given to this test in the configuration.
*
* Learn more about [test retries](https://playwright.dev/docs/test-retries#retries).
* Location in the source where the test is defined.
*/
retries: number;
location: Location;
/**
* Contains the repeat index when running in "repeat each" mode. This mode is enabled by passing `--repeat-each` to the
* [command line](https://playwright.dev/docs/test-cli).
* Whether the test is considered running fine. Non-ok tests fail the test run with non-zero exit code.
*/
repeatEachIndex: number;
/**
* Results for each run of this test.
*/
results: TestResult[];
ok(): boolean;
/**
* Testing outcome for this test. Note that outcome is not the same as
* [testResult.status](https://playwright.dev/docs/api/class-testresult#test-result-status):
* - Test that is expected to fail and actually fails is `'expected'`.
* - Test that passes on a second retry is `'flaky'`.
*/
outcome(): 'skipped' | 'expected' | 'unexpected' | 'flaky';
outcome(): "skipped"|"expected"|"unexpected"|"flaky";
/**
* Whether the test is considered running fine. Non-ok tests fail the test run with non-zero exit code.
* Suite this test case belongs to.
*/
ok(): boolean;
}
parent: Suite;
/**
* Contains the repeat index when running in "repeat each" mode. This mode is enabled by passing `--repeat-each` to the
* [command line](https://playwright.dev/docs/test-cli).
*/
repeatEachIndex: number;
/**
* Results for each run of this test.
*/
results: Array<TestResult>;
/**
* The maximum number of retries given to this test in the configuration.
*
* Learn more about [test retries](https://playwright.dev/docs/test-retries#retries).
*/
retries: number;
/**
* The timeout given to the test. Affected by
* [testConfig.timeout](https://playwright.dev/docs/api/class-testconfig#test-config-timeout),
* [testProject.timeout](https://playwright.dev/docs/api/class-testproject#test-project-timeout),
* [test.setTimeout(timeout)](https://playwright.dev/docs/api/class-test#test-set-timeout),
* [test.slow()](https://playwright.dev/docs/api/class-test#test-slow-1) and
* [testInfo.setTimeout(timeout)](https://playwright.dev/docs/api/class-testinfo#test-info-set-timeout).
*/
timeout: number;
/**
* Test title as passed to the [test.(call)(title, testFunction)](https://playwright.dev/docs/api/class-test#test-call)
* call.
*/
title: string;
/**
* Returns a list of titles from the root down to this test.
*/
titlePath(): Array<string>;}
/**
* A result of a single [TestCase] run.
*/
export interface TestResult {
/**
* When test is retries multiple times, each retry attempt is given a sequential number.
*
* Learn more about [test retries](https://playwright.dev/docs/test-retries#retries).
*/
retry: number;
/**
* Index of the worker where the test was run.
*
* Learn more about [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test.
*/
workerIndex: number;
/**
* Start time of this particular test run.
*/
startTime: Date;
/**
* Running time in milliseconds.
*/
duration: number;
/**
* The status of this test result. See also
* [testCase.expectedStatus](https://playwright.dev/docs/api/class-testcase#test-case-expected-status).
*/
status: TestStatus;
/**
* First error thrown during test execution, if any. This is equal to the first element in
* [testResult.errors](https://playwright.dev/docs/api/class-testresult#test-result-errors).
*/
error?: TestError;
/**
* Errors thrown during the test execution.
*/
errors: TestError[];
/**
* The list of files or buffers attached during the test execution through
* [testInfo.attachments](https://playwright.dev/docs/api/class-testinfo#test-info-attachments).
*/
attachments: { name: string, path?: string, body?: Buffer, contentType: string }[];
/**
* Anything written to the standard output during the test run.
*/
stdout: (string | Buffer)[];
/**
* Anything written to the standard error during the test run.
*/
stderr: (string | Buffer)[];
/**
* List of steps inside this test run.
*/
steps: TestStep[];
}
attachments: Array<{
/**
* Attachment name.
*/
name: string;
/**
* Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`.
*/
contentType: string;
/**
* Optional path on the filesystem to the attached file.
*/
path?: string;
/**
* Optional attachment body used instead of a file.
*/
body?: Buffer;
}>;
/**
* Represents a step in the [TestRun].
*/
export interface TestStep {
/**
* User-friendly test step title.
*/
title: string;
/**
* Returns a list of step titles from the root step down to this step.
*/
titlePath(): string[];
/**
* Location in the source where the step is defined.
*/
location?: Location;
/**
* Parent step, if any.
*/
parent?: TestStep;
/**
* Step category to differentiate steps with different origin and verbosity. Built-in categories are:
* - `hook` for fixtures and hooks initialization and teardown
* - `expect` for expect calls
* - `pw:api` for Playwright API calls.
* - `test.step` for test.step API calls.
*/
category: string,
/**
* Start time of this particular test step.
*/
startTime: Date;
/**
* Running time in milliseconds.
*/
duration: number;
/**
* An error thrown during the step execution, if any.
* Optional first error thrown during test execution, if any. This is equal to the first element in
* [testResult.errors](https://playwright.dev/docs/api/class-testresult#test-result-errors).
*/
error?: TestError;
/**
* List of steps inside this step.
* Errors thrown during the test execution.
*/
steps: TestStep[];
data: { [key: string]: any };
}
errors: Array<TestError>;
/**
* When test is retries multiple times, each retry attempt is given a sequential number.
*
* Learn more about [test retries](https://playwright.dev/docs/test-retries#retries).
*/
retry: number;
/**
* Start time of this particular test run.
*/
startTime: Date;
/**
* Anything written to the standard error during the test run.
*/
stderr: Array<string|Buffer>;
/**
* Anything written to the standard output during the test run.
*/
stdout: Array<string|Buffer>;
/**
* List of steps inside this test run.
*/
steps: Array<TestStep>;
/**
* Index of the worker where the test was run.
*
* Learn more about [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test.
*/
workerIndex: number;}
/**
* Result of the full test run.
@ -442,5 +428,78 @@ export interface Reporter {
export {};
/**
* Represents a location in the source code where [TestCase] or [Suite] is defined.
*/
export interface Location {
/**
* Path to the source file.
*/
file: string;
/**
* Line number in the source file.
*/
line: number;
/**
* Column number in the source file.
*/
column: number;
}
/**
* Represents a step in the [TestRun].
*/
export interface TestStep {
/**
* Step category to differentiate steps with different origin and verbosity. Built-in categories are:
* - `hook` for fixtures and hooks initialization and teardown
* - `expect` for expect calls
* - `pw:api` for Playwright API calls.
* - `test.step` for test.step API calls.
*/
category: string;
/**
* Running time in milliseconds.
*/
duration: number;
/**
* Optional location in the source where the step is defined.
*/
location?: Location;
/**
* Optional error thrown during the step execution, if any.
*/
error?: TestError;
/**
* Optional parent step, if any.
*/
parent?: TestStep;
/**
* Start time of this particular test step.
*/
startTime: Date;
/**
* List of steps inside this step.
*/
steps: Array<TestStep>;
/**
* User-friendly test step title.
*/
title: string;
/**
* Returns a list of step titles from the root step down to this step.
*/
titlePath(): Array<string>;
}

View File

@ -95,13 +95,14 @@ class ApiParser {
if (!returnType)
returnType = new Documentation.Type('void');
const comments = extractComments(spec);
let member;
if (match[1] === 'event')
member = Documentation.Member.createEvent(extractLangs(spec), name, returnType, extractComments(spec));
member = Documentation.Member.createEvent(extractLangs(spec), name, returnType, comments);
if (match[1] === 'property')
member = Documentation.Member.createProperty(extractLangs(spec), name, returnType, extractComments(spec));
member = Documentation.Member.createProperty(extractLangs(spec), name, returnType, comments, guessRequired(md.render(comments)));
if (match[1] === 'method' || match[1] === 'async method') {
member = Documentation.Member.createMethod(extractLangs(spec), name, [], returnType, extractComments(spec));
member = Documentation.Member.createMethod(extractLangs(spec), name, [], returnType, comments);
if (match[1] === 'async method')
member.async = true;
}

View File

@ -32,22 +32,29 @@ Error.stackTraceLimit = 50;
class TypesGenerator {
/**
* @param {Documentation} documentation
* @param {{
* documentation: Documentation,
* classNames: Set<string>,
* overridesToDocsClassMapping: Map<string, string>,
* ignoreMissing: Set<string>,
* }} options
*/
constructor(documentation) {
constructor(options) {
/** @type {Array<{name: string, properties: Member[]}>} */
this.objectDefinitions = [];
/** @type {Set<string>} */
this.handledMethods = new Set();
this.documentation = documentation;
this.documentation = options.documentation;
this.classNames = options.classNames;
this.overridesToDocsClassMapping = options.overridesToDocsClassMapping;
this.ignoreMissing = options.ignoreMissing;
}
/**
* @param {string} overridesFile
* @param {Map<string, string>=} docsOnlyClassMapping
* @returns {Promise<string>}
*/
async generateTypes(overridesFile, docsOnlyClassMapping) {
async generateTypes(overridesFile) {
this.documentation.filterForLanguage('js');
this.documentation.copyDocsFromSuperclasses([]);
@ -82,22 +89,22 @@ class TypesGenerator {
const handledClasses = new Set();
let overrides = await parseOverrides(overridesFile, className => {
const docClass = this.docClassForName(className, docsOnlyClassMapping);
const docClass = this.docClassForName(className);
if (!docClass)
return '';
handledClasses.add(className);
return this.writeComment(docClass.comment) + '\n';
}, (className, methodName, overloadIndex) => {
const docClass = this.docClassForName(className, docsOnlyClassMapping);
const docClass = this.docClassForName(className);
let method;
if (docClass) {
const methods = docClass.membersArray.filter(m => m.alias === methodName && m.kind !== 'event').sort((a, b) => a.overloadIndex - b.overloadIndex);
// Use the last overload when not enough overloads are defined in docs.
method = methods.find(m => m.overloadIndex === overloadIndex) || methods[methods.length - 1];
}
if (docsOnlyClassMapping && !method)
if (!method && this.canIgnoreMissingName(`${className}.${methodName}`))
return '';
this.handledMethods.add(`${className}.${methodName}`);
this.handledMethods.add(`${className}.${methodName}#${overloadIndex}`);
if (!method) {
if (new Set(['on', 'addListener', 'off', 'removeListener', 'once']).has(methodName))
return '';
@ -105,12 +112,15 @@ class TypesGenerator {
}
return this.memberJSDOC(method, ' ').trimLeft();
}, (className) => {
const docClass = this.docClassForName(className, docsOnlyClassMapping);
return (!docsOnlyClassMapping && docClass) ? this.classBody(docClass) : '';
const docClass = this.docClassForName(className);
if (!docClass || !this.classNames.has(docClass.name))
return '';
return this.classBody(docClass);
});
const IGNORED_CLASSES = ['PlaywrightAssertions', 'LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'ScreenshotAssertions'];
const classes = this.documentation.classesArray.filter(cls => !IGNORED_CLASSES.includes(cls.name)).filter(cls => !handledClasses.has(cls.name));
const classes = this.documentation.classesArray
.filter(cls => this.classNames.has(cls.name))
.filter(cls => !handledClasses.has(cls.name));
{
const playwright = this.documentation.classesArray.find(c => c.name === 'Playwright');
playwright.membersArray = playwright.membersArray.filter(member => !['errors', 'devices'].includes(member.name));
@ -121,7 +131,7 @@ class TypesGenerator {
`// This file is generated by ${__filename.substring(path.join(__dirname, '..', '..').length).split(path.sep).join(path.posix.sep)}`,
overrides,
'',
docsOnlyClassMapping ? '' : classes.map(classDesc => {
classes.map(classDesc => {
return (classDesc.name === 'Playwright') ? this.classBody(classDesc, true) : this.classToString(classDesc);
}).join('\n'),
this.objectDefinitionsToString(overrides),
@ -131,12 +141,20 @@ class TypesGenerator {
/**
* @param {string} name
* @param {Map<string, string> | undefined} docsOnlyClassMapping
*/
docClassForName(name, docsOnlyClassMapping) {
name = (docsOnlyClassMapping ? docsOnlyClassMapping.get(name) : undefined) || name;
const docClass = this.documentation.classes.get(name);
if (!docClass && !docsOnlyClassMapping)
canIgnoreMissingName(name) {
const parts = name.split('.');
// Either the class is ignored, or a specific method.
return this.ignoreMissing.has(name) || this.ignoreMissing.has(parts[0]);
}
/**
* @param {string} name
*/
docClassForName(name) {
const mappedName = (this.overridesToDocsClassMapping ? this.overridesToDocsClassMapping.get(name) : undefined) || name;
const docClass = this.documentation.classes.get(mappedName);
if (!docClass && !this.canIgnoreMissingName(name))
throw new Error(`Unknown override class ${name}`);
return docClass;
}
@ -265,26 +283,26 @@ class TypesGenerator {
if (member.async)
type = `Promise<${type}>`;
// do this late, because we still want object definitions for overridden types
if (!this.hasOwnMethod(classDesc, member.alias))
if (!this.hasOwnMethod(classDesc, member))
return '';
if (exportMembersAsGlobals) {
const memberType = member.kind === 'method' ? `${args} => ${type}` : type;
return `${jsdoc}${exportMembersAsGlobals ? 'export const ' : ''}${member.alias}: ${memberType};`
}
return `${jsdoc}${member.alias}${args}: ${type};`
return `${jsdoc}${member.alias}${member.required ? '' : '?'}${args}: ${type};`
}).filter(x => x).join('\n\n'));
return parts.join('\n');
}
/**
* @param {Documentation.Class} classDesc
* @param {string} methodName
* @param {Documentation.Member} member
*/
hasOwnMethod(classDesc, methodName) {
if (this.handledMethods.has(`${classDesc.name}.${methodName}`))
hasOwnMethod(classDesc, member) {
if (this.handledMethods.has(`${classDesc.name}.${member.alias}#${member.overloadIndex}`))
return false;
while (classDesc = this.parentClass(classDesc)) {
if (classDesc.members.has(methodName))
if (classDesc.members.has(member.alias))
return false;
}
return true;
@ -479,9 +497,15 @@ class TypesGenerator {
fs.mkdirSync(testTypesDir)
writeFile(path.join(coreTypesDir, 'protocol.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'packages', 'playwright-core', 'src', 'server', 'chromium', 'protocol.d.ts'), 'utf8'));
const assertionClasses = new Set(['PlaywrightAssertions', 'LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'ScreenshotAssertions']);
const apiDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
apiDocumentation.index();
const apiTypesGenerator = new TypesGenerator(apiDocumentation);
const apiTypesGenerator = new TypesGenerator({
documentation: apiDocumentation,
classNames: new Set(apiDocumentation.classesArray.map(cls => cls.name).filter(name => !assertionClasses.has(name))),
overridesToDocsClassMapping: new Map(),
ignoreMissing: new Set(),
});
let apiTypes = await apiTypesGenerator.generateTypes(path.join(__dirname, 'overrides.d.ts'));
const namedDevices = Object.keys(devices).map(name => ` ${JSON.stringify(name)}: DeviceDescriptor;`).join('\n');
apiTypes += [
@ -504,25 +528,41 @@ class TypesGenerator {
const testOnlyDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
const testDocumentation = apiDocumentation.mergeWith(testOnlyDocumentation);
const testTypesGenerator = new TypesGenerator(testDocumentation);
const testClassMapping = new Map([
['TestType', 'Test'],
['Config', 'TestConfig'],
['FullConfig', 'TestConfig'],
['Project', 'TestProject'],
['PlaywrightWorkerOptions', 'TestOptions'],
['PlaywrightTestOptions', 'TestOptions'],
['PlaywrightWorkerArgs', 'Fixtures'],
['PlaywrightTestArgs', 'Fixtures'],
]);
let testTypes = await testTypesGenerator.generateTypes(path.join(__dirname, 'overrides-test.d.ts'), testClassMapping);
const testTypesGenerator = new TypesGenerator({
documentation: testDocumentation,
classNames: new Set(['TestError', 'TestInfo', 'WorkerInfo']),
overridesToDocsClassMapping: new Map([
['TestType', 'Test'],
['Config', 'TestConfig'],
['FullConfig', 'TestConfig'],
['Project', 'TestProject'],
['PlaywrightWorkerOptions', 'TestOptions'],
['PlaywrightTestOptions', 'TestOptions'],
['PlaywrightWorkerArgs', 'Fixtures'],
['PlaywrightTestArgs', 'Fixtures'],
]),
ignoreMissing: new Set([
'FullConfig.version',
'FullConfig.rootDir',
'SuiteFunction',
'TestFunction',
'PlaywrightWorkerOptions.defaultBrowserType',
'PlaywrightWorkerArgs.playwright',
]),
});
let testTypes = await testTypesGenerator.generateTypes(path.join(__dirname, 'overrides-test.d.ts'));
testTypes = testTypes.replace(/( +)\n/g, '\n'); // remove trailing whitespace
writeFile(path.join(testTypesDir, 'test.d.ts'), testTypes);
const testReporterOnlyDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api'));
const testReporterDocumentation = testDocumentation.mergeWith(testReporterOnlyDocumentation);
const testReporterTypesGenerator = new TypesGenerator(testReporterDocumentation);
let testReporterTypes = await testReporterTypesGenerator.generateTypes(path.join(__dirname, 'overrides-testReporter.d.ts'), new Map());
const testReporterTypesGenerator = new TypesGenerator({
documentation: testReporterDocumentation,
classNames: new Set(testReporterOnlyDocumentation.classesArray.map(cls => cls.name)),
overridesToDocsClassMapping: new Map(),
ignoreMissing: new Set(['FullResult']),
});
let testReporterTypes = await testReporterTypesGenerator.generateTypes(path.join(__dirname, 'overrides-testReporter.d.ts'));
testReporterTypes = testReporterTypes.replace(/( +)\n/g, '\n'); // remove trailing whitespace
writeFile(path.join(testTypesDir, 'testReporter.d.ts'), testReporterTypes);

View File

@ -187,67 +187,16 @@ export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
export type TestStatus = 'passed' | 'failed' | 'timedOut' | 'skipped';
export interface TestError {
message?: string;
stack?: string;
value?: string;
}
export interface WorkerInfo {
config: FullConfig;
parallelIndex: number;
project: FullProject;
workerIndex: number;
}
export interface TestInfo {
config: FullConfig;
parallelIndex: number;
project: FullProject;
workerIndex: number;
title: string;
titlePath: string[];
file: string;
line: number;
column: number;
fn: Function;
skip(): void;
skip(condition: boolean): void;
skip(condition: boolean, description: string): void;
fixme(): void;
fixme(condition: boolean): void;
fixme(condition: boolean, description: string): void;
fail(): void;
fail(condition: boolean): void;
fail(condition: boolean, description: string): void;
slow(): void;
slow(condition: boolean): void;
slow(condition: boolean, description: string): void;
setTimeout(timeout: number): void;
expectedStatus: TestStatus;
timeout: number;
annotations: { type: string, description?: string }[];
attachments: { name: string, path?: string, body?: Buffer, contentType: string }[];
attach(name: string, options?: { contentType?: string, path?: string, body?: string | Buffer }): Promise<void>;
repeatEachIndex: number;
retry: number;
duration: number;
status?: TestStatus;
error?: TestError;
errors: TestError[];
stdout: (string | Buffer)[];
stderr: (string | Buffer)[];
snapshotSuffix: string;
snapshotDir: string;
outputDir: string;
snapshotPath: (...pathSegments: string[]) => string;
outputPath: (...pathSegments: string[]) => string;
}
interface SuiteFunction {
@ -280,15 +229,11 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
fixme(condition: boolean, description?: string): void;
fixme(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void;
fail(): void;
fail(condition: boolean): void;
fail(condition: boolean, description: string): void;
fail(callback: (args: TestArgs & WorkerArgs) => boolean): void;
fail(callback: (args: TestArgs & WorkerArgs) => boolean, description: string): void;
fail(condition: boolean, description?: string): void;
fail(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void;
slow(): void;
slow(condition: boolean): void;
slow(condition: boolean, description: string): void;
slow(callback: (args: TestArgs & WorkerArgs) => boolean): void;
slow(callback: (args: TestArgs & WorkerArgs) => boolean, description: string): void;
slow(condition: boolean, description?: string): void;
slow(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void;
setTimeout(timeout: number): void;
beforeEach(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise<any> | any): void;
afterEach(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise<any> | any): void;

View File

@ -17,63 +17,16 @@
import type { FullConfig, FullProject, TestStatus, TestError } from './test';
export type { FullConfig, TestStatus, TestError } from './test';
export interface Location {
file: string;
line: number;
column: number;
}
export interface Suite {
parent?: Suite;
title: string;
location?: Location;
suites: Suite[];
tests: TestCase[];
titlePath(): string[];
allTests(): TestCase[];
project(): FullProject | undefined;
}
export interface TestCase {
parent: Suite;
title: string;
location: Location;
titlePath(): string[];
expectedStatus: TestStatus;
timeout: number;
annotations: { type: string, description?: string }[];
retries: number;
repeatEachIndex: number;
results: TestResult[];
outcome(): 'skipped' | 'expected' | 'unexpected' | 'flaky';
ok(): boolean;
}
export interface TestResult {
retry: number;
workerIndex: number;
startTime: Date;
duration: number;
status: TestStatus;
error?: TestError;
errors: TestError[];
attachments: { name: string, path?: string, body?: Buffer, contentType: string }[];
stdout: (string | Buffer)[];
stderr: (string | Buffer)[];
steps: TestStep[];
}
export interface TestStep {
title: string;
titlePath(): string[];
location?: Location;
parent?: TestStep;
category: string,
startTime: Date;
duration: number;
error?: TestError;
steps: TestStep[];
data: { [key: string]: any };
}
/**

View File

@ -117,7 +117,7 @@ async function parseOverrides(filePath, commentForClass, commentForMethod, extra
pos,
text: commentForMethod(className, `${prefix}`, 0),
});
} else if (!ts.isMethodSignature(node)) {
} else if (ts.isIntersectionTypeNode(node) || ts.isTypeLiteralNode(node)) {
ts.forEachChild(node, child => visitProperties(className, prefix, child));
}
}