chrome-devtools-frontend
Version:
Chrome DevTools UI
128 lines (113 loc) • 3.78 kB
text/typescript
// Copyright 2025 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {readFileSync} from 'fs';
import glob from 'glob';
import * as ts from 'typescript';
import yargs from 'yargs';
import {hideBin} from 'yargs/helpers';
const argv = yargs(hideBin(process.argv))
.option('format', {
alias: 'f',
describe: 'Output format',
choices: ['list', 'b'],
default: 'list',
})
.option('sources', {
type: 'array',
alias: 's',
describe: 'Sources',
choices: ['devtools', 'chromium'],
default: ['devtools', 'chromium'],
})
.parseSync();
/**
* Usage: node --no-warnings --experimental-strip-types
* scripts/extract_bugs.ts
*
* Finds all skipped tests and returns associated bug IDs and the test
* files (tab-separated).
*/
const bugs = new Set<string>();
const bugToFile = new Map<string, string>();
function extract(sourceFile: ts.SourceFile) {
extractBugs(sourceFile);
function isSkipCall(node: ts.Node) {
if (node.getChildAt(0).kind === ts.SyntaxKind.PropertyAccessExpression) {
const propAccess = node.getChildAt(0);
const skipCalls = new Set(['it.skip', 'describe.skip', 'itScreenshot.skip']);
if (skipCalls.has(propAccess.getText())) {
return true;
}
}
return false;
}
function isSkipOnPlatformsCall(node: ts.Node) {
if (node.getChildAt(0).kind === ts.SyntaxKind.PropertyAccessExpression) {
const propAccess = node.getChildAt(0);
const skipOnPlatformCalls =
new Set(['it.skipOnPlatforms', 'describe.skipOnPlatforms', 'itScreenshot.skipOnPlatforms']);
if (skipOnPlatformCalls.has(propAccess.getText())) {
return true;
}
}
return false;
}
function extractBugs(node: ts.Node) {
switch (node.kind) {
case ts.SyntaxKind.CallExpression: {
let description;
if (isSkipCall(node)) {
description = node.getChildAt(2).getChildAt(0).getText();
} else if (isSkipOnPlatformsCall(node)) {
description = node.getChildAt(2).getChildAt(2).getText();
}
if (!description) {
break;
}
const match = description.match(/crbug.com\/(\d+)/);
if (!match) {
break;
}
bugs.add(match[1]);
bugToFile.set(match[1], sourceFile.fileName);
break;
}
}
ts.forEachChild(node, extractBugs);
}
}
if (argv.sources.includes('devtools')) {
const files = [
...glob.sync('front_end/**/*.test.ts'),
...glob.sync('test/**/*test.ts'),
];
for (const file of files) {
extract(ts.createSourceFile(
file, readFileSync(file).toString(), ts.ScriptTarget.ESNext,
/* setParentNodes */ true));
}
}
if (argv.sources.includes('chromium')) {
const expectations = readFileSync('../../chromium/src/third_party/blink/web_tests/TestExpectations', 'utf-8');
const lines = expectations.split('\n');
for (const line of lines) {
if (line.includes('/tests/devtools/')) {
const parts = line.split(' ');
const crbug = parts.shift() ?? '';
const match = crbug.match(/crbug.com\/(\d+)/);
if (!match) {
continue;
}
bugs.add(match[1]);
bugToFile.set(match[1], parts.find(part => part.includes('/tests/devtools/')) ?? '');
}
}
}
if (argv.format === 'b') {
console.log(`id: (${Array.from(bugs).join('|')})`);
} else {
for (const bug of bugs) {
console.log(`crbug.com/${bug}\t${bugToFile.get(bug)}`);
}
}