Skip to content

Commit

Permalink
Handle browser / page crash gracefully
Browse files Browse the repository at this point in the history
  • Loading branch information
badeball committed Mar 7, 2024
1 parent 145dde3 commit 4644591
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 3 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
needs: prepare-versions
runs-on: ubuntu-20.04
container:
image: cypress/base:20.5.0
image: cypress/browsers:node-20.5.0-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1
strategy:
matrix:
cypress-version: ${{fromJson(needs.prepare-versions.outputs.matrix)}}
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:
- name: Build
run: npm run build
- name: Test
run: npm run test
run: npm run test:integration -- features/browser_crash.feature
- name: Version
run: npx cypress --version

Expand Down Expand Up @@ -79,4 +79,4 @@ jobs:
- name: Remove Webpack test
run: rm features/loaders/webpack.feature
- name: Test
run: npm run test:integration
run: npm run test:integration -- features/browser_crash.feature
70 changes: 70 additions & 0 deletions features/browser_crash.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
@cypress>=12
Feature: browser crash

# Crash-behavior is a mess, ref. https://github.com/cypress-io/cypress/issues/22631.
# Pre-12.17.0, enabling video recording actually made a difference, ref. https://github.com/cypress-io/cypress/pull/27167.
# Post-12.17.0 behavior seems to be consistent enough that it's testable.

Background:
Given additional preprocessor configuration
"""
{
"json": {
"enabled": true
}
}
"""

Rule: report generation should fail gracefully in the event of a browser crash

Scenario: Chromium process crash
Given a file named "cypress/e2e/a.feature" with:
"""
Feature: a feature
Scenario: a scenario
Given a step
"""
And a file named "cypress/support/step_definitions/steps.js" with:
"""
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
Given("a step", function() {
new Cypress.Promise(() => {
Cypress.automation("remote:debugger:protocol", {
command: "Browser.crash",
});
});
});
"""
When I run cypress with a chromium-family browser
Then it fails
And the output should contain
"""
Due to browser crash, no reports are created for cypress/e2e/a.feature.
"""
And the JSON report shouldn't contain any specs

Scenario: Renderer process crash
Given a file named "cypress/e2e/a.feature" with:
"""
Feature: a feature
Scenario: a scenario
Given a step
"""
And a file named "cypress/support/step_definitions/steps.js" with:
"""
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
Given("a step", function() {
new Cypress.Promise(() => {
Cypress.automation("remote:debugger:protocol", {
command: "Page.crash",
});
});
});
"""
When I run cypress with a chromium-family browser
Then it fails
And the output should contain
"""
Due to browser crash, no reports are created for cypress/e2e/a.feature.
"""
And the JSON report shouldn't contain any specs
15 changes: 15 additions & 0 deletions features/step_definitions/cli_steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import * as glob from "glob";
import ICustomWorld from "../support/ICustomWorld";
import { assertAndReturn } from "../support/helpers";

const isCI = process.env.CI === "true";

function execAsync(
command: string
): Promise<{ stdout: string; stderr: string }> {
Expand Down Expand Up @@ -74,6 +76,19 @@ When(
}
);

When(
"I run cypress with a chromium-family browser",
{ timeout: 60 * 1000 },
async function (this: ICustomWorld) {
/**
* Chrome is installed in CI, Chromium is installed in my (maintainer) environment.
*/
await this.runCypress({
extraArgs: ["--browser", isCI ? "chrome" : "chromium"],
});
}
);

When(
"I run diagnostics",
{ timeout: 60 * 1000 },
Expand Down
34 changes: 34 additions & 0 deletions lib/plugin-event-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,40 @@ export async function afterSpecHandler(
return;
}

/**
* This pretty much can't happen and the check is merely to satisfy TypeScript in the next block.
*/
switch (state.state) {
case "uninitialized":
case "after-run":
throw createError("Unexpected state in afterSpecHandler: " + state.state);
}

const browserCrashExprCol = [
/We detected that the .+ process just crashed/,
/We detected that the .+ Renderer process just crashed/,
];

const error = results.error;

if (error != null && browserCrashExprCol.some((expr) => expr.test(error))) {
console.log(
chalk.yellow(
` Due to browser crash, no reports are created for ${spec.relative}.`
)
);

state = {
state: "after-spec",
pretty: state.pretty,
messages: {
accumulation: state.messages.accumulation,
},
};

return;
}

switch (state.state) {
case "test-finished": // This is the normal case.
case "before-spec": // This can happen if a spec doesn't contain any tests.
Expand Down

0 comments on commit 4644591

Please sign in to comment.