Skip to content

Commit

Permalink
fix: local console errors (#1033)
Browse files Browse the repository at this point in the history
  • Loading branch information
tihuan authored Jul 11, 2024
1 parent 5319564 commit f062d10
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .infra/rdev/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ stack:
services:
explorer:
image:
tag: sha-8128ec3a
tag: sha-7a1f4e0e
replicaCount: 1
env:
# env vars common to all deployment stages
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

46 changes: 42 additions & 4 deletions client/__tests__/e2e/playwright.global.setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import { Page } from "@playwright/test";
import { ConsoleMessage, Page } from "@playwright/test";
import { DATASET_METADATA_RESPONSE } from "../__mocks__/apiMock";

const LOCAL_CONSOLE_ERROR_IGNORE_LIST = [
"window.plausible is not a function",
"net::ERR_NETWORK_CHANGED",
"To locate the bad setState() call inside",
/**
* (thuang): Deep zoom tile load sometimes fails temporarily
*/
"Image load aborted",
"TileSource",
/**
* (thuang): Sometimes `obsoleteBrowsers.js` fails to load temporarily
*/
"obsoleteBrowsers.js",
/**
* (thuang): Sometimes Google Font fails to load temporarily
*/
"https://fonts.googleapis.com",
];

// (seve): mocking required to simulate metadata coming from data-portal needed for navigation header and breadcrumbs

const setup = async ({ page }: { page: Page }) => {
Expand Down Expand Up @@ -42,23 +61,42 @@ const setup = async ({ page }: { page: Page }) => {
},
});
});
/**
* Purpose: Captures console messages such as console.log, console.error, console.warn, etc.
* Use Case: Useful for debugging or monitoring what is being logged to the console by the web page
*/
page.on("console", (message) => {
// if this is running locally don't fail on error
if (process.env.CI !== "true") {
if (
process.env.CI !== "true" &&
isKnownErrors(message, LOCAL_CONSOLE_ERROR_IGNORE_LIST)
) {
return;
}

if (message.type() === "error") {
throw new Error(`CLIENT SIDE ERROR: ${JSON.stringify(message)}`);
throw new Error(

Check failure on line 78 in client/__tests__/e2e/playwright.global.setup.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:238:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › bug fix: invalid lasso cancels lasso overlay

1) [chromium] › e2e/e2e.test.ts:238:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › bug fix: invalid lasso cancels lasso overlay Error: "console.error" ERROR: Failed to load resource: the server responded with a status of 404 (). Full object: {"_page":{"_type":"Page","_guid":"page@49267813009e29548fd335a8959ecd98"},"_event":{"page":{"_events":{},"_eventsCount":11,"_object":{"_type":"Page","_guid":"page@49267813009e29548fd335a8959ecd98"}},"type":"error","text":"Failed to load resource: the server responded with a status of 404 ()","args":[],"location":{"url":"https://cellxgene.dev.single-cell.czi.technology/d/pbmc3k.cxg/static/main-f9eca1697190db8553dc.js","lineNumber":0,"columnNumber":0}}} at e2e/playwright.global.setup.ts:78 76 | 77 | if (message.type() === "error") { > 78 | throw new Error( | ^ 79 | `"console.error" ERROR: ${message.text()}. Full object: ${JSON.stringify( 80 | message 81 | )}` at Page.<anonymous> (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/playwright.global.setup.ts:78:13)

Check failure on line 78 in client/__tests__/e2e/playwright.global.setup.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:238:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › bug fix: invalid lasso cancels lasso overlay

1) [chromium] › e2e/e2e.test.ts:238:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › bug fix: invalid lasso cancels lasso overlay Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: "console.error" ERROR: Failed to load resource: the server responded with a status of 404 (). Full object: {"_page":{"_type":"Page","_guid":"page@6d9baf7ba53efe28c7f9c12d5e77630d"},"_event":{"page":{"_events":{},"_eventsCount":11,"_object":{"_type":"Page","_guid":"page@6d9baf7ba53efe28c7f9c12d5e77630d"}},"type":"error","text":"Failed to load resource: the server responded with a status of 404 ()","args":[],"location":{"url":"https://cellxgene.dev.single-cell.czi.technology/d/pbmc3k.cxg/static/main-f9eca1697190db8553dc.js","lineNumber":0,"columnNumber":0}}} at e2e/playwright.global.setup.ts:78 76 | 77 | if (message.type() === "error") { > 78 | throw new Error( | ^ 79 | `"console.error" ERROR: ${message.text()}. Full object: ${JSON.stringify( 80 | message 81 | )}` at Page.<anonymous> (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/playwright.global.setup.ts:78:13)

Check failure on line 78 in client/__tests__/e2e/playwright.global.setup.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:238:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › bug fix: invalid lasso cancels lasso overlay

1) [chromium] › e2e/e2e.test.ts:238:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › bug fix: invalid lasso cancels lasso overlay Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: "console.error" ERROR: Failed to load resource: the server responded with a status of 404 (). Full object: {"_page":{"_type":"Page","_guid":"page@f7896bc8520218cfa9eaf808a719e7c6"},"_event":{"page":{"_events":{},"_eventsCount":11,"_object":{"_type":"Page","_guid":"page@f7896bc8520218cfa9eaf808a719e7c6"}},"type":"error","text":"Failed to load resource: the server responded with a status of 404 ()","args":[],"location":{"url":"https://cellxgene.dev.single-cell.czi.technology/d/pbmc3k.cxg/static/main-429fb7742fa84882aaae.js","lineNumber":0,"columnNumber":0}}} at e2e/playwright.global.setup.ts:78 76 | 77 | if (message.type() === "error") { > 78 | throw new Error( | ^ 79 | `"console.error" ERROR: ${message.text()}. Full object: ${JSON.stringify( 80 | message 81 | )}` at Page.<anonymous> (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/playwright.global.setup.ts:78:13)

Check failure on line 78 in client/__tests__/e2e/playwright.global.setup.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:227:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › selects all cells cellset 2

2) [chromium] › e2e/e2e.test.ts:227:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › selects all cells cellset 2 Error: "console.error" ERROR: Failed to load resource: the server responded with a status of 404 (). Full object: {"_page":{"_type":"Page","_guid":"page@ed5a62dd111a3d45e8670c4a9be17d03"},"_event":{"page":{"_events":{},"_eventsCount":11,"_object":{"_type":"Page","_guid":"page@ed5a62dd111a3d45e8670c4a9be17d03"}},"type":"error","text":"Failed to load resource: the server responded with a status of 404 ()","args":[],"location":{"url":"https://cellxgene.dev.single-cell.czi.technology/d/pbmc3k.cxg/static/main-f9eca1697190db8553dc.js","lineNumber":0,"columnNumber":0}}} at e2e/playwright.global.setup.ts:78 76 | 77 | if (message.type() === "error") { > 78 | throw new Error( | ^ 79 | `"console.error" ERROR: ${message.text()}. Full object: ${JSON.stringify( 80 | message 81 | )}` at Page.<anonymous> (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/playwright.global.setup.ts:78:13)

Check failure on line 78 in client/__tests__/e2e/playwright.global.setup.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:227:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › selects all cells cellset 2

2) [chromium] › e2e/e2e.test.ts:227:15 › dataset: pbmc3k.cxg › graph instance: layout-graph › cell selection › selects all cells cellset 2 Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: "console.error" ERROR: Failed to load resource: the server responded with a status of 404 (). Full object: {"_page":{"_type":"Page","_guid":"page@47e5a94242ad3755063a03da7c7dbc1f"},"_event":{"page":{"_events":{},"_eventsCount":11,"_object":{"_type":"Page","_guid":"page@47e5a94242ad3755063a03da7c7dbc1f"}},"type":"error","text":"Failed to load resource: the server responded with a status of 404 ()","args":[],"location":{"url":"https://cellxgene.dev.single-cell.czi.technology/d/pbmc3k.cxg/static/main-f9eca1697190db8553dc.js","lineNumber":0,"columnNumber":0}}} at e2e/playwright.global.setup.ts:78 76 | 77 | if (message.type() === "error") { > 78 | throw new Error( | ^ 79 | `"console.error" ERROR: ${message.text()}. Full object: ${JSON.stringify( 80 | message 81 | )}` at Page.<anonymous> (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/playwright.global.setup.ts:78:13)
`"console.error" ERROR: ${message.text()}. Full object: ${JSON.stringify(
message
)}`
);
}
});
/**
* Purpose: Captures unhandled exceptions that occur on the page.
* Use Case: Useful for detecting and debugging runtime errors in the web page's JavaScript
*/
page.on("pageerror", (error) => {
// if this is running locally don't fail on error
if (process.env.CI !== "true") {
return;
}
throw new Error(`UNCAUGHT CLIENT ERROR: ${error}`);
throw new Error(`"pageerror" UNCAUGHT JS exception: ${error}`);
});
};

export default setup;

function isKnownErrors(message: ConsoleMessage, errorList: string[]) {
return errorList.some((error) => JSON.stringify(message).includes(error));
}
70 changes: 37 additions & 33 deletions client/src/components/geneExpression/gene.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from "react";

import { Button, Icon } from "@blueprintjs/core";
import { AnchorButton, Button, Icon } from "@blueprintjs/core";
import { connect } from "react-redux";
import { Icon as InfoCircle, IconButton } from "czifui";
import Truncate from "../util/truncate";
import HistogramBrush from "../brushableHistogram";
import { RootState } from "../../reducers";
import { AppDispatch, RootState } from "../../reducers";

import actions from "../../actions";

Expand All @@ -20,29 +20,30 @@ interface State {
geneIsExpanded: boolean;
}

interface Props {
interface StateProps {
isColorAccessor: boolean;
isScatterplotXXaccessor: boolean;
isScatterplotYYaccessor: boolean;
isGeneInfo: boolean;
}

interface DispatchProps {
dispatch: AppDispatch;
}

interface OwnProps {
gene: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- FIXME
quickGene: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- FIXME
removeGene: any;
quickGene?: boolean;
removeGene?: (gene: string) => () => void;
geneId: DataframeValue;
isGeneExpressionComplete: boolean;
onGeneExpressionComplete: () => void;
geneDescription?: string;
geneset?: string;
}

// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
@connect((state: RootState, ownProps: Props) => {
const { gene } = ownProps;
type Props = StateProps & OwnProps & DispatchProps;

return {
isColorAccessor:
state.colors.colorAccessor === gene &&
state.colors.colorMode !== "color by categorical metadata",
isScatterplotXXaccessor: state.controls.scatterplotXXaccessor === gene,
isScatterplotYYaccessor: state.controls.scatterplotYYaccessor === gene,
};
})
class Gene extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
Expand All @@ -52,7 +53,6 @@ class Gene extends React.Component<Props, State> {
}

onColorChangeClick = (): void => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene } = this.props;
track(EVENTS.EXPLORER_COLORBY_GENE_BUTTON_CLICKED);
dispatch(actions.requestSingleGeneExpressionCountsForColoringPOST(gene));
Expand All @@ -67,7 +67,6 @@ class Gene extends React.Component<Props, State> {

handleSetGeneAsScatterplotX = (): void => {
track(EVENTS.EXPLORER_PLOT_X_BUTTON_CLICKED);
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene } = this.props;
dispatch({
type: "set scatterplot x",
Expand All @@ -77,7 +76,6 @@ class Gene extends React.Component<Props, State> {

handleSetGeneAsScatterplotY = (): void => {
track(EVENTS.EXPLORER_PLOT_Y_BUTTON_CLICKED);
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene } = this.props;
dispatch({
type: "set scatterplot y",
Expand All @@ -86,13 +84,11 @@ class Gene extends React.Component<Props, State> {
};

handleDeleteGeneFromSet = (): void => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene, geneset } = this.props;
dispatch(actions.genesetDeleteGenes(geneset, [gene]));
};

handleDisplayGeneInfo = async (): Promise<void> => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene, geneId } = this.props;
track(EVENTS.EXPLORER_GENE_INFO_BUTTON_CLICKED, {
gene,
Expand Down Expand Up @@ -124,20 +120,15 @@ class Gene extends React.Component<Props, State> {
render(): JSX.Element {
const {
gene,
// @ts-expect-error ts-migrate(2339) FIXME: Property 'geneDescription' does not exist on type ... Remove this comment to see the full error message
geneDescription,
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
isColorAccessor,
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotXXaccessor' does not exist on type ... Remove this comment to see the full error message
isScatterplotXXaccessor,
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotYYaccessor' does not exist on type ... Remove this comment to see the full error message
isScatterplotYYaccessor,
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isGeneInfo' does not exist on type ... Remove this comment to see the full error message
isGeneInfo,
quickGene,
removeGene,
onGeneExpressionComplete,
isGeneExpressionComplete,
isGeneInfo,
} = this.props;
const { geneIsExpanded } = this.state;
const geneSymbolWidth = 60 + (geneIsExpanded ? MINI_HISTOGRAM_WIDTH : 0);
Expand Down Expand Up @@ -183,7 +174,7 @@ class Gene extends React.Component<Props, State> {
</Truncate>
</div>
<div style={{ display: "inline-block", marginLeft: "0" }}>
<Button
<AnchorButton
small
minimal
intent={isGeneInfo ? "primary" : "none"}
Expand All @@ -204,7 +195,7 @@ class Gene extends React.Component<Props, State> {
/>
</div>
</IconButton>
</Button>
</AnchorButton>
</div>
{!geneIsExpanded ? (
<div style={{ width: MINI_HISTOGRAM_WIDTH }}>
Expand All @@ -227,7 +218,7 @@ class Gene extends React.Component<Props, State> {
track(EVENTS.EXPLORER_DELETE_FROM_GENESET_BUTTON_CLICKED);

if (quickGene) {
removeGene(gene)();
removeGene?.(gene)();
} else {
this.handleDeleteGeneFromSet();
}
Expand Down Expand Up @@ -291,4 +282,17 @@ class Gene extends React.Component<Props, State> {
}
}

export default Gene;
export default connect(mapStateToProps)(Gene);

function mapStateToProps(state: RootState, ownProps: OwnProps): StateProps {
const { gene } = ownProps;

return {
isColorAccessor:
state.colors.colorAccessor === gene &&
state.colors.colorMode !== "color by categorical metadata",
isScatterplotXXaccessor: state.controls.scatterplotXXaccessor === gene,
isScatterplotYYaccessor: state.controls.scatterplotYYaccessor === gene,
isGeneInfo: state.controls.gene === gene,
};
}
1 change: 0 additions & 1 deletion client/src/components/geneExpression/geneSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ class GeneSet extends React.Component<{}, State> {
<Gene
key={gene}
gene={gene}
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ key: any; gene: any; geneDescription: any;... Remove this comment to see the full error message
geneDescription={geneDescription}
geneset={setName}
geneId={geneId}
Expand Down
21 changes: 10 additions & 11 deletions client/src/components/geneExpression/quickGene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import fuzzysort from "fuzzysort";
import { Suggest } from "@blueprintjs/select";
import { useSelector, useDispatch } from "react-redux";

import { noop } from "lodash";
import Gene from "./gene";

import { postUserErrorToast } from "../framework/toasters";
Expand Down Expand Up @@ -160,17 +161,15 @@ function QuickGene() {
}

return (
<>
<Gene
key={`quick=${gene}`}
gene={gene}
removeGene={removeGene}
quickGene
geneId={geneId}
isGeneExpressionComplete
onGeneExpressionComplete={() => {}}
/>
</>
<Gene
key={`quick=${gene}`}
gene={gene}
removeGene={removeGene}
quickGene
geneId={geneId}
isGeneExpressionComplete
onGeneExpressionComplete={noop}
/>
);
});
}, [userDefinedGenes, geneNames, geneIds, dispatch]);
Expand Down

0 comments on commit f062d10

Please sign in to comment.