-
Notifications
You must be signed in to change notification settings - Fork 9.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core(tsc): add type checking to runner #4961
Conversation
lighthouse-core/audits/audit.js
Outdated
* @param {LH.Audit.Context} context | ||
* @return {LH.Audit.Product | Promise<LH.Audit.Product>} | ||
*/ | ||
static audit(artifacts, context) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
had to add this to the base class so typescript could see it in runner :)
// If status is good, content must be not null. | ||
if (content === null) { | ||
throw new Error(`Status ${status} was valid, but content was null`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kdzwinel had to add this to keep the type checker happy even though it appears to not be possible. I couldn't think of a good way around this short of adding another property that lets you demonstrate to the type checker that a null content
can't happen in certain cases, e.g.
{error: false, status: number, content: string}|{error: true, status: number|null, content: string|null}
...or we can just test like here for // can't ever happen
:)
runner.js is a lot easier to review at https://github.com/GoogleChrome/lighthouse/pull/4961/files?w=1 |
@@ -27,21 +26,6 @@ function assertTraceEventsEqual(traceEventsA, traceEventsB) { | |||
|
|||
/* eslint-env mocha */ | |||
describe('asset-saver helper', () => { | |||
it('generates HTML', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested by "screenshots html file saved to disk with data" below
@@ -78,15 +61,15 @@ describe('asset-saver helper', () => { | |||
const ssHTMLFilename = 'the_file-0.screenshots.html'; | |||
const ssFileContents = fs.readFileSync(ssHTMLFilename, 'utf8'); | |||
assert.ok(/<!doctype/gim.test(ssFileContents)); | |||
const expectedScreenshotContent = '{"timestamp":674089419.919'; | |||
const expectedScreenshotContent = '{"timestamp":668545858.596'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now really pulling screenshots from the trace instead of having requestScreenshots
resolve on the saved screenshots, which turned out weren't from this trace :)
@@ -522,14 +520,10 @@ describe('Runner', () => { | |||
|
|||
return Runner.run({}, {url, config}).then(results => { | |||
assert.deepEqual(results.artifacts.ViewportDimensions, ViewportDimensions); | |||
|
|||
for (const method of Object.keys(computedArtifacts)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
artifacts from Runner.run()
no longer include computed artifact methods on them. This and below just removes the check that they are on the returned artifacts object
@@ -16,14 +16,14 @@ const clampTo2Decimals = val => Math.round(val * 100) / 100; | |||
class ReportScoring { | |||
/** | |||
* Computes the weighted-average of the score of the list of items. | |||
* @param {!Array<{score: number, weight: number|undefined}>} items | |||
* @param {Array<{score: number, weight: number}>} items |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
turns out we always have score and weight by this point, so letting the type system handle it now
lighthouse-core/audits/audit.js
Outdated
* | ||
* @param {LH.Artifacts} artifacts | ||
* @param {LH.Audit.Context} context | ||
* @return {LH.Audit.Product | Promise<LH.Audit.Product>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
satisfying to have this documented. :)
typings/result.d.ts
Outdated
/** | ||
* The full output of a Lighthouse run. | ||
*/ | ||
export interface Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename file lhr.d.t.s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
typings/result.d.ts
Outdated
*/ | ||
export interface Result { | ||
/** | ||
* The URL that was supplied to Lighthouse and initially navigated to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use single line for these. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
typings/result.d.ts
Outdated
/** | ||
* Description of the runtime configuration used for gathering these results. | ||
*/ | ||
runtimeConfig: Result.RuntimeConfig; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets add a bit more whitespace (and even a comment?) to separate lhr-non-lite
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -30,15 +30,6 @@ describe('ReportScoring', () => { | |||
{score: 0.2, weight: 1}, | |||
]), 0.04); | |||
}); | |||
|
|||
it('should work for missing values', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah... :) we assert before here that things have a score so I agree with not worrying about this case.
} | ||
|
||
/** | ||
* A LH Artifacts object, but the traces and devtoolsLogs are replaced |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u add a comment that this is present to support a legacy usecase. and link to the docs
was confused for a sec why runner artifacts were in here. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we agree to nuke this use case before v3? it's a lot of config complexity for no known customers other than our tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup. we discussed yesterday that this is basically solved via
settings: { auditMode: 'path/to/artifacts/' }
patrick, that in line with your config/settings harmonization?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup exactly 👍
* @param {{config: LH.Config, url: string, initialUrl?: string, driverMock?: Driver}} opts | ||
* @return {Promise<RunnerResult|undefined>} | ||
*/ | ||
static async run(connection, opts) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opts
now never leaves run()
and _gatherArtifactsFromBrowser()
, so we have a lot more freedom to do things like refactor our url
/initialUrl
/finalUrl
business (not to mention options.settings
(now isolated to _gatherArtifactsFromBrowser()
) vs options.config.settings
, etc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very impressed with your commitment to appropriately back-ticking tokens in this sentence.
👨💻 ⌨️ 🥇
* Reference to an audit member of a category and how its score should be | ||
* weighted and how its results grouped with other members. | ||
*/ | ||
export interface CategoryMemberJson { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as LH.Result.Category.CategoryMember
can we avoid defining it twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we avoid defining it twice?
this is mostly mental organization that can be cleaned up when we add types to config.js
. I'm not sure what we'll need by the end of things, so it was easier to keep separate for now.
Even if they end up exactly the same, we may still want two separate type names, one for acceptable input to config.js
and one for what comes out. @patrickhulce mentions he uses something like typename
and typenameUnsafe
, and something like that might make it more obvious what the difference is. Though hopefully in our case you'll never see a *Json
type inside of anything called by runner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay gotcha. can we do a comment like
Object shape maintained all the way to LH.Result.Category.CategoryMember
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I guess that's the answer to why there's a LH.Config.CategoryMember
and a LH.Config.CategoryMemberJson
.
For why there's an identical LH.Result.CategoryMember
, I'm not sure what the best thing to do is. We don't have to define it twice (or three times :), but it does mean that if we add a property to one and not the other in the future we can just do that (instead of splitting the definition later and having to figure out which one we meant wherever we refer to it). I'm also not sure which name should win.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a comment and TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay. I think the resolution here is that we ideally split Config and ConfigJSON into two .d.ts
files. (and I'd favor a clearer module split for all the JSON buddies to keep them separate from what new Config()
returns. \o/
audits: CategoryMemberJson[]; | ||
} | ||
|
||
export interface GroupJson { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as LH.Result.Group
typings/config.d.ts
Outdated
} | ||
|
||
// For now, these are unchanged from JSON version | ||
export interface CategoryMember extends CategoryMemberJson {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in addition to the doubled-up type (LH.Result.Category.CategoryMember
), this has two names?
* @param {!LH.ConfigSettings} settings | ||
* @return {!Object} runtime config | ||
* @param {LH.Config.Settings} settings | ||
* @return {LH.Result.RuntimeConfig} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's possible we want to just move this to the report generator now that we have more readable throttling information in config settings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree. not much left in this fn.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, we should just output the settings used into the LHR :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added to #4333
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runner feels great. Nice!
I'm into the changes in scoring.
The instantiateComputedArtifacts change is quite nice too. As discussed, this sets up nicely to move our request*
methods onto Audit
and off artifacts
in the future. :D
lighthouse-core/runner.js
Outdated
static _saveArtifacts(artifacts, path) { | ||
return assetSaver.saveArtifacts(artifacts, path); | ||
const driver = runnerOpts.driverMock || new Driver(connection); | ||
const options = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you already renamed opts
to runnerOpts
, though in the parent context is still has the opts
name.
Regardless, feels like we can do gatherOpts
for this guy. eviscerate all the options
. woo!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boom done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is great! made a few comments, but overall lgtm
@@ -162,9 +162,13 @@ async function prepareAssets(artifacts, audits) { | |||
for (const passName of passNames) { | |||
const trace = artifacts.traces[passName]; | |||
const devtoolsLog = artifacts.devtoolsLogs[passName]; | |||
|
|||
// Avoid Runner->AssetSaver->Runner circular require by loading Runner here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, really disappointed to get there and run into that. Hopefully with computedArtifacts
refactor that'll get cleaned up
lighthouse-core/runner.js
Outdated
try { | ||
parsedURL = new URL(opts.url); | ||
} catch (e) { | ||
const err = new Error('The url provided should have a proper protocol and hostname.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can probably just throw directly here
* @param {!LH.ConfigSettings} settings | ||
* @return {!Object} runtime config | ||
* @param {LH.Config.Settings} settings | ||
* @return {LH.Result.RuntimeConfig} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, we should just output the settings used into the LHR :D
categories?: Record<string, Config.Category>; | ||
groups?: Record<string, Config.Group>; | ||
// TODO(bckenny): should be Partial<> maybe? don't want to fail imported json | ||
artifacts?: Artifacts; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial sgtm now 👍
} | ||
|
||
/** | ||
* A LH Artifacts object, but the traces and devtoolsLogs are replaced |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we agree to nuke this use case before v3? it's a lot of config complexity for no known customers other than our tests
/** | ||
* A description of configuration used for gathering. | ||
*/ | ||
export interface RuntimeConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah let's totally replace this with settings and have report renderer handle it
I'll follow up with the artifacts removal. Any other feedback? |
also adds
result.d.ts
to type the full LHR and adds more types toconfig.d.ts
(though it still needs a lot of work in combo with typingconfig.js
).