1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-05-15 07:06:52 +02:00

Tests for playground are using a mock response (#2611)

The official playground quite often provides a timeout error as in
https://github.com/google/comprehensive-rust/issues/2549

This is mocking/overriding the response from the playground for success
and failure messages to avoid the server provided timeouts. As far as I
see most responses from the playground are delivered below 10 seconds
(but varies a lot...)

There still might be timeouts and I know of the following knobs that can
be tuned
- wdio waits for 10 seconds until it aborts the current attemp (e.g. to
wait for the text to be as expected)

347de61d13/tests/wdio.conf.ts (L98)
- another timeout is the 15 second timeout for fetching the result from
the playground - this is not overriden by the mock (currently, pending
https://github.com/webdriverio/webdriverio/issues/14090 which would
allow for an immediate mock response without waiting for the remote
endpoint)

347de61d13/theme/book.js (L31)
This commit is contained in:
michael-kerscher 2025-02-06 12:33:33 +01:00 committed by GitHub
parent 553e3c5b10
commit 4ec257942e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,106 @@
import { $, browser } from "@wdio/globals";
export default class Playground {
/**
* stores a playground mock
*/
mock: WebdriverIO.Mock;
get area() {
return $(".ace_content");
}
get start_button() {
return $("button.play-button");
}
get stderr() {
return $("code.result.stderr");
}
get stdout() {
return $("code.result.stdout");
}
/**
* activate the playground by clicking into it
*/
async activate() {
// clicking into the content is necessary for the button to be displayed
await this.area.waitForClickable();
await this.area.click();
}
/**
* run the code in the playground editor
*/
async run() {
// clicking the button triggers action
await this.start_button.waitForClickable();
// await browser.debug();
await this.start_button.click();
}
/**
* generate a new mock for the playground that overrides playground requests
*/
async mock_new() {
return browser.mock("https://play.rust-lang.org/execute", {
method: "post",
});
}
/**
* reset the mock object
*/
async mock_reset() {
this.mock.clear();
}
/**
* mock a successful playground run
* @param stdout a string that is expected to be in stdout
*/
async mock_success(stdout: string) {
this.mock = await this.mock_new();
// be aware that there is a still a preflight OPTIONS request
this.mock.respond(
{
success: true,
exitDetail: "Exited with status 0",
stdout: stdout,
stderr:
" Compiling playground v0.0.1 (/playground)\n Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.62s\n Running `target/debug/playground`\n",
},
{
headers: {
"Access-Control-Allow-Origin": "*",
},
fetchResponse: false,
}
);
}
/**
* mock a failed run that would be caused if a `fn fail()` is added without any function body
*/
async mock_fail() {
// mock the response so this test does not rely on the playground backend to be working
this.mock = await this.mock_new();
// be aware that there is a still a preflight OPTIONS request
this.mock.respond(
{
success: false,
exitDetail: "Exited with status 101",
stdout: "",
stderr:
' Compiling playground v0.0.1 (/playground)\nerror: expected one of `->`, `where`, or `{`, found `}`\n --> src/main.rs:5:1\n |\n4 | fn fail()\n | ---- - expected one of `->`, `where`, or `{`\n | |\n | while parsing this `fn`\n5 | }\n | ^ unexpected token\n\nerror: free function without a body\n --> src/main.rs:4:5\n |\n4 | fn fail()\n | ^^^^^^^^^- help: provide a definition for the function: `{ <body> }`\n\nerror: could not compile `playground` (bin "playground") due to 2 previous errors\n',
},
{
headers: {
"Access-Control-Allow-Origin": "*",
},
fetchResponse: false,
}
);
}
}

View File

@ -0,0 +1,49 @@
import { describe, it } from "mocha";
import { expect, browser } from "@wdio/globals";
import { Key } from "webdriverio";
import Playground from "./objects/playground";
describe("Playground", () => {
beforeEach(async () => {
// this page contains a hello world playground
await browser.url("/hello-world/hello-world.html");
});
it("exists and is shown but output fields do not yet exist", async () => {
const playground = new Playground();
// ensure a playground exists and pre-state is as expected
await expect(playground.area).toExist();
await expect(playground.start_button).toExist();
await expect(playground.start_button).not.toBeDisplayed();
await expect(playground.stderr).not.toExist();
await expect(playground.stdout).not.toExist();
});
it("executes the hello world code and prints the hello message", async () => {
const playground = new Playground();
await playground.mock_success("Hello world!\n");
await playground.activate();
await playground.run();
await expect(playground.stdout).toBeDisplayed();
await expect(playground.stderr).not.toBeDisplayed();
await expect(playground.stdout).toHaveText("Hello world!");
});
it("shows error messages in stderr if the code is broken", async () => {
const playground = new Playground();
await playground.mock_fail();
await playground.activate();
// append some failing code to the editor that is now in focus
await browser.keys([Key.Enter, "fn expect_failure()"]);
await playground.run();
await expect(playground.stdout).toBeDisplayed();
await expect(playground.stderr).toBeDisplayed();
// check for error message in stderr
await expect(playground.stderr).toHaveText(
expect.stringContaining("error: could not compile")
);
await expect(playground.stdout).toHaveText("No output");
});
});