-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Adds NewRun tests #242
Adds NewRun tests #242
Conversation
f56e4ab
to
c1acc7c
Compare
Pull Request Test Coverage Report for Build 337
💛 - Coveralls |
Pull Request Test Coverage Report for Build 310
💛 - Coveralls |
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 excellent coverage! Thanks!
{pipeline && (pipeline.parameters || []).map((param, i) => | ||
<TextField key={i} variant='outlined' label={param.name} value={param.value || ''} | ||
{pipeline.parameters.map((param, i) => | ||
<TextField id={`newRunPipelineParam${i}`} key={i} variant='outlined' |
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 a little excessive to have an id per field only to enable tests. They can use the parent's selector plus an nth-child
kind of selector instead?
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.
Is there any real harm here though? I'll take full responsibility if there's ever a collision with newRunPipelineParamX
, and IDs make it so much more deterministic
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.
No harm, just a matter of style. :) I'm ok leaving these around.
@@ -225,7 +230,8 @@ class NewRun extends Page<{}, NewRunState> { | |||
experimentId = RunUtils.getFirstExperimentReferenceId(originalRun.run); | |||
} | |||
} catch (err) { | |||
await this.showPageError(`Error: failed to get original run: ${originalRunId}.`, err); | |||
await this.showPageError(`Error: failed to retrieve original run: ${originalRunId}.`, err); | |||
logger.error(`Failed to retrieve original run: ${originalRunId}`, err); |
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.
Console log doesn't really contain any more details in this case.
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 below. I think it's only useful to console log the error if we don't have a way of showing to the user yet, so we can ask them to get more details from the console while filing an issue.
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 think it does. When we call showPageError
, we end up only using the error's message, but when we log it with logger, we include the full stacktrace as well
@@ -113,6 +115,9 @@ class PipelineSelector extends React.Component<PipelineSelectorProps, PipelineSe | |||
logger.error('Could not get list of pipelines', errorMessage); | |||
} | |||
|
|||
// Warnings are showing up here in tests when the NewRun component is unmounted before being | |||
// closed, saying setState is being called after the component is unmounted. | |||
// The warning doesn't show up when actually using the app though. |
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 setStateSafe
? Here and elsewhere.
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.
Doing some reading, it sounds like that's not how we should be handling this, and that mostly just hides the warning, see: https://reactjs.org/blog/2015/12/16/ismounted-antipattern.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.
Yes, we should be looking at canceling promises on unmount, but that's an expensive fix. I don't see a lot of down sides to this, other than just be a little ugly.
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.
Also forgot to mention, the setStateSafe function is only available for Page
components, though i could emulate it here fairly easily
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.
Yes, we probably should. I'll open an issue for properly fixing this, although we shouldn't really be holding our breath to do it. It might not be the best way to handle this, but it's not a bad fix IMO.
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.
Do you want me to do add that code to this component for this PR then?
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.
Up to you, it's probably not a lot of code so I'd do it, but it's fine to do this separately too.
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.
Suite! Thanks. :)
/lgtm
/approve
await this.showPageError(`Error: failed to retrieve pipeline with ID: ${pipelineId}.`, err); | ||
logger.error(`Error: failed to retrieve pipeline with ID: ${pipelineId}`, err); | ||
this.setState({ pipelineSelectorOpen: false }, async () => { | ||
const errorMessage = await errorToMessage(err); |
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.
Separately, I wonder if errorToMessage
should be called within showErrorDialog
too.
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.
yes, that probably makes sense. we do it already for page errors
@@ -38,19 +37,23 @@ class TestNewRun extends NewRun { | |||
} | |||
|
|||
describe('NewRun', () => { | |||
const consoleErrorSpy = jest.spyOn(console, 'error'); |
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 looking at this, I'm wondering how this works. I can see the same thing appears in other suites, but if we're not resetting the spy, how come spying on a spy doesn't fail?
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.
Aren't I resetting it below in the beforeEach
?
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.
Yes, but that's beforeEach
, which means when this suite is done, the method will be mocked. I'm not sure what's happening here, perhaps it's getting reset automatically or something.
frontend/src/pages/NewRun.test.tsx
Outdated
const createJobSpy = jest.spyOn(Apis.jobServiceApi, 'createJob'); | ||
const createRunSpy = jest.spyOn(Apis.runServiceApi, 'createRun'); | ||
const getExperimentSpy = jest.spyOn(Apis.experimentServiceApi, 'getExperiment'); | ||
const getPipelineSpy = jest.spyOn(Apis.pipelineServiceApi, 'getPipeline'); | ||
const getRunSpy = jest.spyOn(Apis.runServiceApi, 'getRun'); | ||
const historyPushSpy = jest.fn(); | ||
const historyReplaceSpy = jest.fn(); | ||
const listPipelinesSpy = jest.spyOn(Apis.pipelineServiceApi, 'listPipelines'); |
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.
How come we don't need this? Shouldn't we get an error that fetch
has failed when the pipeline selector opens? Or do we never use mount in tests below, never actually rendering the selector?
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.
Not sure. There are some tests where we fully mount the tree, and interact with the selector, but it doesn't seem to be a problem. perhaps it's related to the peculiarities of Dialog
that was preventing us from testing the "dismiss" paths?
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: yebrahim The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
1 similar comment
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: yebrahim The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
With this PR, the
NewRun
file has nearly complete coverage (by lines).A little cleanup is done within the
NewExperiment
test as well.The
_prepareFormFromClone()
function inNewRun
did not actually change except that the wrapping if-block was changed to just return on the negative condition.We no longer attempt to change the query params in
handleChange
when the pipelineID changes as it only would be called during a clone flow, and there's no real reason to do it.This change is