Skip to content
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

Setup Storybook for testing UI components #1497

Merged
merged 8 commits into from Sep 8, 2022
Merged

Conversation

koesie10
Copy link
Member

@koesie10 koesie10 commented Sep 6, 2022

This sets up Storybook for testing of React components. It adds stories for some of the MRVA components. It does not add stories for the main MRVA views since those are not independent of VSCode and need to be run from within VSCode.

Screen.Recording.2022-09-06.at.10.59.49.mov

Checklist

  • CHANGELOG.md has been updated to incorporate all user visible changes made by this pull request.
  • Issues have been created for any UI or other user-facing changes made by this pull request.
  • [Maintainers only] If this pull request makes user-facing changes that require documentation changes, open a corresponding docs pull request in the github/codeql repo and add the ready-for-doc-review label there.

This sets up Storybook for testing of React components. It adds stories
for some of the MRVA components. It does not add stories for the main
MRVA views since those are not independent of VSCode and need to be run
from within VSCode.
@koesie10 koesie10 added the secexp label Sep 6, 2022
@koesie10 koesie10 requested a review from a team September 6, 2022 09:02
@koesie10 koesie10 requested a review from a team as a code owner September 6, 2022 09:02
@charisk
Copy link
Contributor

charisk commented Sep 6, 2022

It does not add stories for the main MRVA views since those are not independent of VSCode and need to be run from within VSCode

Do you think it's possible to fake out being inside VS Code? From a very simplistic point of view, the webviews are "just" web pages rendered inside VS Code. I appreciate that reality is much more nuanced, but I was hoping we'd look into potentially setting up the whatever we need within Storybook to pretend we're inside the VS Code extension. I don't think we'll have many components that are completely independent of VS Code unfortunately.

@koesie10
Copy link
Member Author

koesie10 commented Sep 6, 2022

It does not add stories for the main MRVA views since those are not independent of VSCode and need to be run from within VSCode

Do you think it's possible to fake out being inside VS Code? From a very simplistic point of view, the webviews are "just" web pages rendered inside VS Code. I appreciate that reality is much more nuanced, but I was hoping we'd look into potentially setting up the whatever we need within Storybook to pretend we're inside the VS Code extension. I don't think we'll have many components that are completely independent of VS Code unfortunately.

We might be able to simulate some of VSCode's environment, or at least mock the function calls so that they are not undefined. However, I think this should not be necessary. For example, the RemoteQueries component is currently dependent on data received from VSCode:

export function RemoteQueries(): JSX.Element {
const [queryResult, setQueryResult] = useState<RemoteQueryResult>(emptyQueryResult);
const [analysesResults, setAnalysesResults] = useState<AnalysisResults[]>([]);
const [sort, setSort] = useState<Sort>('name');
useEffect(() => {
window.addEventListener('message', (evt: MessageEvent) => {
if (evt.origin === window.origin) {
const msg: ToRemoteQueriesMessage = evt.data;
if (msg.t === 'setRemoteQueryResult') {
setQueryResult(msg.queryResult);
} else if (msg.t === 'setAnalysesResults') {
setAnalysesResults(msg.analysesResults);
}
} else {
// sanitize origin
const origin = evt.origin.replace(/\n|\r/g, '');
console.error(`Invalid event origin ${origin}`);
}
});
});
if (!queryResult) {
return <div>Waiting for results to load.</div>;
}
try {
return (
<div className="vscode-codeql__remote-queries">
<ThemeProvider colorMode="auto">
<ViewTitle>{queryResult.queryTitle}</ViewTitle>
<QueryInfo {...queryResult} />
<Failures {...queryResult} />
<Summary
queryResult={queryResult}
analysesResults={analysesResults}
sort={sort}
setSort={setSort} />
<AnalysesResults
queryResult={queryResult}
analysesResults={analysesResults}
totalResults={queryResult.totalResultCount}
sort={sort} />
</ThemeProvider>
</div>
);
} catch (err) {
console.error(err);
return <div>There was an error displaying the view.</div>;
}
}

Rather than simulating sending a message to the window, I think we should change the components to have a very clear separation between UI and the VSCode communication. So, this component would take a queryResult and analysesResults prop. Then the only dependency on VSCode is when you click a button, for example:

const downloadAllAnalysesResults = (query: RemoteQueryResult) => {
vscode.postMessage({
t: 'remoteQueryDownloadAllAnalysesResults',
analysisSummaries: query.analysisSummaries
});
};

We can probably simulate this to be an action to Storybook instead. However, that still means we won't really be able to test this flow:

  1. Click on "Download all" button
  2. The spinner shows
  3. When it is finished, the button disappears

I don't think this is necessarily a problem since we can make different stories with the state of the UI in these three states, but it is something to be aware of.

@charisk
Copy link
Contributor

charisk commented Sep 6, 2022

We might be able to simulate some of VSCode's environment, or at least mock the function calls so that they are not undefined. However, I think this should not be necessary.

I agree. We could design our components to be not directly use VS Code function calls. I was thinking more in terms of styling etc rather than interactivity e.g. so that we're able to use VS Code colour variables etc.

@koesie10
Copy link
Member Author

koesie10 commented Sep 6, 2022

We might be able to simulate some of VSCode's environment, or at least mock the function calls so that they are not undefined. However, I think this should not be necessary.

I agree. We could design our components to be not directly use VS Code function calls. I was thinking more in terms of styling etc rather than interactivity e.g. so that we're able to use VS Code colour variables etc.

VSCode colour variables do completely work (see https://github.com/github/vscode-codeql/pull/1497/files#diff-9b6fe650c4162362634b90f6d2fec716787e077e6db1febcd621986c5633155e), it's just the JavaScript window/vscode objects which do not match/do not exist which are normally inserted by VSCode.

This allows us to add a story for the "main" remote queries view.
@koesie10
Copy link
Member Author

koesie10 commented Sep 7, 2022

I've now added a mock of the VSCode API available in the webview, so we can now also render views which depend on the VSCode API:

Screenshot 2022-09-07 at 14 40 12

Copy link
Contributor

@charisk charisk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for looking into this and getting all the bits working! It looks great and it will really improve our DX while building our new components and views!

extensions/ql-vscode/.npmrc Show resolved Hide resolved
// Allow all stories/components to use Codicons
import '@vscode/codicons/dist/codicon.css';

import '../src/stories/vscode-theme.css';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having our own file that we have to manage/keep up-to date etc., is there a way to get everything from VSCode automatically?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might be able to generate it from the VSCode source code, but I don't think we can import it from VSCode itself.

The colors are defined here and the styles are created here. They are then injected into the WebView using this on the host side and this on the WebView side.

I think it will be a lot more work to generate the CSS variables from this than to copy the variables from VSCode once in a while.

Copy link
Contributor

@charisk charisk Sep 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's a shame. I suspected it would be a can of worms, but I thought I'd ask anyway 😂

In that case I think we should have some docs to tell people about this (maybe in the storybook part in the README?) and how to update them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I can also add it to an Overview page in Storybook itself and refer to that from the CONTRIBUTING documentation?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just had a brainwave! Feel free to ignore this if you want (totally up to you), but the actual toolkit has a storybook, so perhaps this is something they've solved already? See https://github.com/microsoft/vscode-webview-ui-toolkit/tree/main/.storybook

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did see whether it was possible to replicate the way they are using the VSCode variables, but they are using a completely custom system. They have a system of "design tokens" (https://github.com/microsoft/vscode-webview-ui-toolkit/blob/6fc339ce26e7da15b9ba97c063f56d8a4eae85ad/src/design-tokens.ts) which specify a variable and a default. These are then used in the styles and will automatically use either the variable or the default. I don't think that is going to work for us since we'd need to modify the way we write the CSS files and set defaults for all variables we use. It could also result in having different defaults than the toolkit, so it might also get out of sync at some point.

extensions/ql-vscode/.storybook/preview.js Outdated Show resolved Hide resolved
extensions/ql-vscode/.storybook/preview.js Outdated Show resolved Hide resolved
extensions/ql-vscode/.storybook/preview.js Outdated Show resolved Hide resolved
extensions/ql-vscode/.storybook/preview.js Outdated Show resolved Hide resolved
@koesie10 koesie10 requested a review from a team September 7, 2022 15:08
Copy link
Contributor

@charisk charisk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm approving and leaving the last 2 unresolved comments up to you to look at or ignore!

Again, thanks for sorting this!

@koesie10
Copy link
Member Author

koesie10 commented Sep 8, 2022

The failing Dependency Review is due to dependencies of Storybook and is only used in dev environments. It would be quite hard to fix this since the dependencies are transitive dependencies of Storybook. Since they won't be used in production code, I think it should be fine to merge this.

@koesie10 koesie10 merged commit 24652a8 into main Sep 8, 2022
@koesie10 koesie10 deleted the koesie10/storybook branch September 8, 2022 08:38
@charisk
Copy link
Contributor

charisk commented Sep 8, 2022

The failing Dependency Review is due to dependencies of Storybook and is only used in dev environments. It would be quite hard to fix this since the dependencies are transitive dependencies of Storybook. Since they won't be used in production code, I think it should be fine to merge this.

Does this mean that all future PRs will have a failing check?

@koesie10
Copy link
Member Author

koesie10 commented Sep 8, 2022

The failing Dependency Review is due to dependencies of Storybook and is only used in dev environments. It would be quite hard to fix this since the dependencies are transitive dependencies of Storybook. Since they won't be used in production code, I think it should be fine to merge this.

Does this mean that all future PRs will have a failing check?

No, the check only checks new dependencies, so future PRs will not fail this check. We already have some open Dependabot alerts for other development dependencies and those do not fail any PRs either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants