chore: remove src/api.ts (#6191)

Now the async hooks helper is gone api.ts was only used by the coverage
tools and by doclint.

DocLint is nearing the end of its lifespan with the TSDoc work, so I
focused on how best to define a list of modules for the coverage
tooling. They define an object of classes, and the path to that module.
They need the full path because we also check if the module exports any
events that need to be emitted - the coverage tool asserts that the
emitting of those events is also tested.

It's not _great_ that DocLint relies on a constant defined in the
coverage utils, but it should only be this way for a short period of
time and no one is actively working on DocLint (bar the effort to remove
it) so I don't think this is worth worrying about.

This change also broke the DocLint tests; based on the fact that DocLint is on its way out it doesn't feel worth fixing the tests, so this commit also removes them.
This commit is contained in:
Jack Franklin 2020-07-10 10:07:28 +01:00 committed by GitHub
parent 03a87e814d
commit f666be3f5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 57 additions and 633 deletions

View File

@ -65,7 +65,6 @@ jobs:
script:
- npm run compare-protocol-d-ts
- npm run lint
- npm run test-doclint
- npm run ensure-new-docs-up-to-date
# This bot runs separately as it changes package.json to test puppeteer-core

View File

@ -13,8 +13,7 @@
"assert-unit-coverage": "cross-env COVERAGE=1 mocha --config mocha-config/coverage-tests.js",
"funit": "PUPPETEER_PRODUCT=firefox npm run unit",
"debug-unit": "node --inspect-brk test/test.js",
"test-doclint": "mocha --config mocha-config/doclint-tests.js",
"test": "npm run tsc && npm run lint --silent && npm run unit-with-coverage && npm run test-doclint && npm run test-types",
"test": "npm run tsc && npm run lint --silent && npm run unit-with-coverage && npm run test-types",
"prepare": "node typescript-if-required.js",
"prepublishOnly": "npm run tsc",
"dev-install": "npm run tsc && node install.js",

View File

@ -1,48 +0,0 @@
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* This file is used in one place:
* 1) the coverage-utils use it to gain a list of all methods we check for test
* coverage on
*/
module.exports = {
Accessibility: require('./common/Accessibility').Accessibility,
Browser: require('./common/Browser').Browser,
BrowserContext: require('./common/Browser').BrowserContext,
BrowserFetcher: require('./node/BrowserFetcher').BrowserFetcher,
CDPSession: require('./common/Connection').CDPSession,
ConsoleMessage: require('./common/ConsoleMessage').ConsoleMessage,
Coverage: require('./common/Coverage').Coverage,
Dialog: require('./common/Dialog').Dialog,
ElementHandle: require('./common/JSHandle').ElementHandle,
ExecutionContext: require('./common/ExecutionContext').ExecutionContext,
EventEmitter: require('./common/EventEmitter').EventEmitter,
FileChooser: require('./common/FileChooser').FileChooser,
Frame: require('./common/FrameManager').Frame,
JSHandle: require('./common/JSHandle').JSHandle,
Keyboard: require('./common/Input').Keyboard,
Mouse: require('./common/Input').Mouse,
Page: require('./common/Page').Page,
Puppeteer: require('./common/Puppeteer').Puppeteer,
HTTPRequest: require('./common/HTTPRequest').HTTPRequest,
HTTPResponse: require('./common/HTTPResponse').HTTPResponse,
SecurityDetails: require('./common/SecurityDetails').SecurityDetails,
Target: require('./common/Target').Target,
TimeoutError: require('./common/Errors').TimeoutError,
Touchscreen: require('./common/Input').Touchscreen,
Tracing: require('./common/Tracing').Tracing,
WebWorker: require('./common/WebWorker').WebWorker,
};

View File

@ -34,13 +34,43 @@ const path = require('path');
const fs = require('fs');
/**
* @param {Map<string, boolean>} apiCoverage
* @param {Object} events
* @param {string} className
* @param {!Object} classType
* This object is also used by DocLint to know which classes to check are
* documented. It's a pretty hacky solution but DocLint is going away soon as
* part of the TSDoc migration.
*/
function traceAPICoverage(apiCoverage, events, className, classType) {
className = className.substring(0, 1).toLowerCase() + className.substring(1);
const MODULES_TO_CHECK_FOR_COVERAGE = {
Accessibility: '../src/common/Accessibility',
Browser: '../src/common/Browser',
BrowserContext: '../src/common/Browser',
BrowserFetcher: '../src/node/BrowserFetcher',
CDPSession: '../src/common/Connection',
ConsoleMessage: '../src/common/ConsoleMessage',
Coverage: '../src/common/Coverage',
Dialog: '../src/common/Dialog',
ElementHandle: '../src/common/JSHandle',
ExecutionContext: '../src/common/ExecutionContext',
EventEmitter: '../src/common/EventEmitter',
FileChooser: '../src/common/FileChooser',
Frame: '../src/common/FrameManager',
JSHandle: '../src/common/JSHandle',
Keyboard: '../src/common/Input',
Mouse: '../src/common/Input',
Page: '../src/common/Page',
Puppeteer: '../src/common/Puppeteer',
HTTPRequest: '../src/common/HTTPRequest',
HTTPResponse: '../src/common/HTTPResponse',
SecurityDetails: '../src/common/SecurityDetails',
Target: '../src/common/Target',
TimeoutError: '../src/common/Errors',
Touchscreen: '../src/common/Input',
Tracing: '../src/common/Tracing',
WebWorker: '../src/common/WebWorker',
};
function traceAPICoverage(apiCoverage, className, modulePath) {
const loadedModule = require(modulePath);
const classType = loadedModule[className];
if (!classType || !classType.prototype) {
console.error(
`Coverage error: could not find class for ${className}. Is src/api.ts up to date?`
@ -63,8 +93,14 @@ function traceAPICoverage(apiCoverage, events, className, classType) {
});
}
if (events[classType.name]) {
for (const event of Object.values(events[classType.name])) {
/**
* If classes emit events, those events are exposed via an object in the same
* module named XEmittedEvents, where X is the name of the class. For example,
* the Page module exposes PageEmittedEvents.
*/
const eventsName = `${className}EmittedEvents`;
if (loadedModule[eventsName]) {
for (const event of Object.values(loadedModule[eventsName])) {
if (typeof event !== 'symbol')
apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, false);
}
@ -108,10 +144,11 @@ const trackCoverage = () => {
return {
beforeAll: () => {
const api = require('../src/api');
const events = require('../src/common/Events');
for (const [className, classType] of Object.entries(api))
traceAPICoverage(coverageMap, events, className, classType);
for (const [className, moduleFilePath] of Object.entries(
MODULES_TO_CHECK_FOR_COVERAGE
)) {
traceAPICoverage(coverageMap, className, moduleFilePath);
}
},
afterAll: () => {
writeCoverage(coverageMap);
@ -122,4 +159,5 @@ const trackCoverage = () => {
module.exports = {
trackCoverage,
getCoverageResults,
MODULES_TO_CHECK_FOR_COVERAGE,
};

View File

@ -18,6 +18,9 @@ const jsBuilder = require('./JSBuilder');
const mdBuilder = require('./MDBuilder');
const Documentation = require('./Documentation');
const Message = require('../Message');
const {
MODULES_TO_CHECK_FOR_COVERAGE,
} = require('../../../test/coverage-utils');
const EXCLUDE_PROPERTIES = new Set([
'Browser.create',
@ -39,10 +42,7 @@ const EXCLUDE_PROPERTIES = new Set([
module.exports = async function lint(page, mdSources, jsSources) {
const mdResult = await mdBuilder(page, mdSources);
const jsResult = await jsBuilder(jsSources);
const jsDocumentation = filterJSDocumentation(
jsSources,
jsResult.documentation
);
const jsDocumentation = filterJSDocumentation(jsResult.documentation);
const mdDocumentation = mdResult.documentation;
const jsErrors = jsResult.errors;
@ -124,14 +124,11 @@ function checkSorting(doc) {
}
/**
* @param {!Array<!Source>} jsSources
* @param {!Documentation} jsDocumentation
* @returns {!Documentation}
*/
function filterJSDocumentation(jsSources, jsDocumentation) {
const apijs = jsSources.find((source) => source.name() === 'api.js');
let includedClasses = null;
if (apijs) includedClasses = new Set(Object.keys(require(apijs.filePath())));
function filterJSDocumentation(jsDocumentation) {
const includedClasses = new Set(Object.keys(MODULES_TO_CHECK_FOR_COVERAGE));
// Filter private classes and methods.
const classes = [];
for (const cls of jsDocumentation.classesArray) {

View File

@ -1,2 +0,0 @@
result-actual.txt
result-diff.html

View File

@ -1,15 +0,0 @@
### class: Bar
### class: Foo
#### foo.test()
#### foo.test()
#### foo.title(arg, arg)
- `arg` <[number]>
- `arg` <[number]>
### class: Bar
[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type "Number"

View File

@ -1,13 +0,0 @@
class Foo {
test() {
}
/**
* @param {number} arg
*/
title(arg) {
}
}
class Bar {
}

View File

@ -1,3 +0,0 @@
[MarkDown] Duplicate declaration of method Foo.test()
[MarkDown] Duplicate declaration of argument Foo.title "arg"
[MarkDown] Duplicate declaration of class Bar

View File

@ -1,14 +0,0 @@
### class: Foo
#### foo.asyncFunction()
#### foo.return42()
#### foo.returnNothing()
- returns: <[number]>
#### foo.www()
- returns <[string]>
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type "Number"

View File

@ -1,20 +0,0 @@
class Foo {
return42() {
return 42;
}
returnNothing() {
let e = () => {
return 10;
}
e();
}
www() {
if (1 === 1)
return 'df';
}
async asyncFunction() {
}
}

View File

@ -1,4 +0,0 @@
[MarkDown] foo.www() has mistyped 'return' type declaration: expected exactly 'returns: ', found 'returns '.
[MarkDown] Method Foo.asyncFunction is missing return type description
[MarkDown] Method Foo.return42 is missing return type description
[MarkDown] Method Foo.returnNothing has unneeded description of return type

View File

@ -1,8 +0,0 @@
const Events = {
Foo: {
a: 'a',
b: 'b',
c: 'c',
},
};
module.exports = {Events};

View File

@ -1,15 +0,0 @@
### class: Foo
#### event: 'c'
#### event: 'a'
#### foo.aaa()
#### event: 'b'
#### foo.ddd
#### foo.ccc()
#### foo.bbb()

View File

@ -1,12 +0,0 @@
class Foo {
constructor() {
this.ddd = 10;
}
aaa() {}
bbb() {}
ccc() {}
}

View File

@ -1,4 +0,0 @@
[MarkDown] Events should go first. Event 'b' in class Foo breaks order
[MarkDown] Event 'c' in class Foo breaks alphabetic ordering of events
[MarkDown] Bad alphabetic ordering of Foo members: Foo.ddd should go after Foo.ccc()
[MarkDown] Bad alphabetic ordering of Foo members: Foo.ccc() should go after Foo.bbb()

View File

@ -1,14 +0,0 @@
### class: Foo
#### foo.bar(options)
- `options` <[Object]>
- `visibility` <[boolean]>
#### foo.foo(arg1, arg2)
- `arg1` <[string]>
- `arg2` <[string]>
#### foo.test(...files)
- `...filePaths` <...[string]>
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object "Object"
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type "Boolean"

View File

@ -1,19 +0,0 @@
class Foo {
/**
* @param {string} arg1
*/
foo(arg1, arg3 = {}) {
}
/**
* @param {...string} filePaths
*/
test(...filePaths) {
}
/**
* @param {{visibility?: boolean}} options
*/
bar(options) {
}
}

View File

@ -1,4 +0,0 @@
[MarkDown] Heading arguments for "foo.test(...files)" do not match described ones, i.e. "...files" != "...filePaths"
[MarkDown] Method Foo.foo() fails to describe its parameters:
- Argument not found: arg3
- Non-existing argument found: arg2

View File

@ -1,5 +0,0 @@
### class: Foo
### class: Bar
### class: Baz

View File

@ -1,2 +0,0 @@
class Foo {
}

View File

@ -1,2 +0,0 @@
class Other {
}

View File

@ -1,3 +0,0 @@
[MarkDown] Non-existing class found: Bar
[MarkDown] Non-existing class found: Baz
[MarkDown] Class not found: Other

View File

@ -1,8 +0,0 @@
const Events = {
Foo: {
Start: 'start',
Finish: 'finish',
},
};
module.exports = {Events};

View File

@ -1,5 +0,0 @@
### class: Foo
#### event: 'start'
#### event: 'stop'

View File

@ -1,3 +0,0 @@
class Foo {
}

View File

@ -1,2 +0,0 @@
[MarkDown] Non-existing event found in class Foo: 'stop'
[MarkDown] Event not found in class Foo: 'finish'

View File

@ -1,10 +0,0 @@
### class: Foo
#### foo.$()
#### foo.money$$money()
#### foo.proceed()
#### foo.start()

View File

@ -1,16 +0,0 @@
class Foo {
start() {
}
stop() {
}
get zzz() {
}
$() {
}
money$$money() {
}
}

View File

@ -1,3 +0,0 @@
[MarkDown] Non-existing method found: Foo.proceed()
[MarkDown] Method not found: Foo.stop()
[MarkDown] Property not found: Foo.zzz

View File

@ -1,5 +0,0 @@
### class: Foo
#### foo.a
#### foo.c

View File

@ -1,7 +0,0 @@
class Foo {
constructor() {
this.a = 42;
this.b = 'hello';
this.emit('done');
}
}

View File

@ -1,2 +0,0 @@
[MarkDown] Non-existing property found: Foo.c
[MarkDown] Property not found: Foo.b

View File

@ -1,6 +0,0 @@
const Events = {
A: {
AnEvent: 'anevent'
},
};
module.exports = { Events };

View File

@ -1,13 +0,0 @@
class A {
constructor(delegate) {
this.property1 = 1;
this._property2 = 2;
}
get getter() {
return null;
}
async method(foo, bar) {
}
}

View File

@ -1,50 +0,0 @@
{
"classes": [
{
"name": "A",
"members": [
{
"name": "anevent",
"kind": "event"
},
{
"name": "property1",
"type": {
"name": "number"
},
"kind": "property"
},
{
"name": "getter",
"type": {
"name": "Object"
},
"kind": "property"
},
{
"name": "method",
"type": {
"name": "Promise"
},
"kind": "method",
"args": [
{
"name": "foo",
"type": {
"name": "Object"
},
"kind": "property"
},
{
"name": "bar",
"type": {
"name": "Object"
},
"kind": "property"
}
]
}
]
}
]
}

View File

@ -1,8 +0,0 @@
const Events = {
B: {
// Event with the same name as a super class method.
foo: 'foo',
},
};
module.exports = {Events};

View File

@ -1,15 +0,0 @@
class A {
constructor() {
}
foo(a) {
}
bar() {
}
}
class B extends A {
bar(override) {
}
}

View File

@ -1,61 +0,0 @@
{
"classes": [
{
"name": "A",
"members": [
{
"name": "foo",
"kind": "method",
"args": [
{
"name": "a",
"type": {
"name": "Object"
},
"kind": "property"
}
]
},
{
"name": "bar",
"kind": "method"
}
]
},
{
"name": "B",
"members": [
{
"name": "foo",
"kind": "event"
},
{
"name": "bar",
"kind": "method",
"args": [
{
"name": "override",
"type": {
"name": "Object"
},
"kind": "property"
}
]
},
{
"name": "foo",
"kind": "method",
"args": [
{
"name": "a",
"type": {
"name": "Object"
},
"kind": "property"
}
]
}
]
}
]
}

View File

@ -1,24 +0,0 @@
### class: Foo
This is a class.
#### event: 'frame'
- <[Frame]>
This event is dispatched.
#### foo.$(selector)
- `selector` <[string]> A selector to query page for
- returns: <[Promise]<[ElementHandle]>>
The method runs document.querySelector.
#### foo.url
- <[string]>
Contains the URL of the request.
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
[Promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise "Promise"
[ElementHandle]: # "ElementHandle"
[ElementHandle]: # "Frame"

View File

@ -1,39 +0,0 @@
{
"classes": [
{
"name": "Foo",
"members": [
{
"name": "frame",
"type": {
"name": "[Frame]"
},
"kind": "event"
},
{
"name": "$",
"type": {
"name": "Promise<ElementHandle>"
},
"kind": "method",
"args": [
{
"name": "selector",
"type": {
"name": "string"
},
"kind": "property"
}
]
},
{
"name": "url",
"type": {
"name": "string"
},
"kind": "property"
}
]
}
]
}

View File

@ -1,125 +0,0 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const path = require('path');
const puppeteer = require('../../../..');
const checkPublicAPI = require('..');
const Source = require('../../Source');
const mdBuilder = require('../MDBuilder');
const jsBuilder = require('../JSBuilder');
const expect = require('expect')
const GoldenUtils = require('../../../../test/golden-utils');
const testUtils = require('../../../../test/utils')
describe('DocLint Public API', function() {
let browser;
let page;
before(async function() {
browser = await puppeteer.launch();
page = await browser.newPage();
});
after(async function() {
await browser.close();
});
describe('checkPublicAPI', function() {
it('diff-classes', testLint('diff-classes'));
it('diff-methods', testLint('diff-methods'));
it('diff-properties', testLint('diff-properties'));
it('diff-arguments', testLint('diff-arguments'));
it('diff-events', testLint('diff-events'));
it('check-duplicates', testLint('check-duplicates'));
it('check-sorting', testLint('check-sorting'));
it('check-returns', testLint('check-returns'));
it('js-builder-common', testJSBuilder('js-builder-common'));
it('js-builder-inheritance', testJSBuilder('js-builder-inheritance'));
it('md-builder-common', testMDBuilder('md-builder-common'));
});
function testLint(testName) {
return async () => {
const dirPath = path.join(__dirname, testName);
testUtils.extendExpectWithToBeGolden(dirPath, dirPath)
const mdSources = await Source.readdir(dirPath, '.md');
const jsSources = await Source.readdir(dirPath, '.js');
const messages = await checkPublicAPI(page, mdSources, jsSources);
const errors = messages.map(message => message.text);
expect(errors.join('\n')).toBeGolden('result.txt');
}
}
function testMDBuilder(testName) {
return async () => {
const dirPath = path.join(__dirname, testName);
testUtils.extendExpectWithToBeGolden(dirPath, dirPath);
const sources = await Source.readdir(dirPath, '.md');
const { documentation } = await mdBuilder(page, sources);
expect(serialize(documentation)).toBeGolden('result.txt');
}
}
function testJSBuilder(testName) {
return async () => {
const dirPath = path.join(__dirname, testName);
testUtils.extendExpectWithToBeGolden(dirPath, dirPath);
const sources = await Source.readdir(dirPath, '.js');
const { documentation } = await jsBuilder(sources);
expect(serialize(documentation)).toBeGolden('result.txt');
}
}
/**
* @param {import('../Documentation')} doc
*/
function serialize(doc) {
const result = {
classes: doc.classesArray.map(cls => ({
name: cls.name,
members: cls.membersArray.map(serializeMember)
}))
};
return JSON.stringify(result, null, 2);
}
/**
* @param {import('../Documentation').Member} member
*/
function serializeMember(member) {
return {
name: member.name,
type: serializeType(member.type),
kind: member.kind,
args: member.argsArray.length ? member.argsArray.map(serializeMember) : undefined
}
}
/**
* @param {import('../Documentation').Type} type
*/
function serializeType(type) {
if (!type)
return undefined;
return {
name: type.name,
properties: type.properties.length ? type.properties.map(serializeMember) : undefined
}
}
})