diff --git a/tests/src/objects/playground.ts b/tests/src/objects/playground.ts new file mode 100644 index 000000000000..169bf6816928 --- /dev/null +++ b/tests/src/objects/playground.ts @@ -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: `{ }`\n\nerror: could not compile `playground` (bin "playground") due to 2 previous errors\n', + }, + { + headers: { + "Access-Control-Allow-Origin": "*", + }, + fetchResponse: false, + } + ); + } +} diff --git a/tests/src/playground.test.ts b/tests/src/playground.test.ts new file mode 100644 index 000000000000..182031efe594 --- /dev/null +++ b/tests/src/playground.test.ts @@ -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"); + }); +});