Skip to content

chore(site): add remote playwright support and script #10445

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

Merged
merged 6 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/contributing/frontend.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,23 @@ to test if the page is being rendered correctly, you should consider using the
> ℹ️ For scenarios where you need to be authenticated, you can use
> `test.use({ storageState: getStatePath("authState") })`.

For ease of debugging, it's possible to run a Playwright test in headful mode
running a Playwright server on your local machine, and executing the test inside
your workspace.

You can either run `scripts/remote_playwright.sh` from `coder/coder` on your
local machine, or execute the following command if you don't have the repo
available:

```bash
bash <(curl -sSL https://raw.githubusercontent.com/coder/coder/main/scripts/remote_playwright.sh) [workspace]
```

The `scripts/remote_playwright.sh` script will start a Playwright server on your
local machine and forward the necessary ports to your workspace. At the end of
the script, you will land _inside_ your workspace with environment variables set
so you can simply execute the test (`pnpm run playwright:test`).

### Integration

Test user interactions like "Click in a button shows a dialog", "Submit the form
Expand Down
83 changes: 83 additions & 0 deletions scripts/remote_playwright.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
set -euo pipefail

workspace=${1:-}
coder_repo=${2:-.}
port=${3:-3000}

if [[ -z "${workspace}" ]]; then
echo "Usage: $0 <workspace> [workspace coder/coder dir] [e2e port]"
exit 1
fi

main() {
# Check the Playwright version from the workspace so we have a 1-to-1 match
# between the current branch and what we're going to run locally. This is
# necessary because Playwright uses their own protocol for communicating
# between the server and client, and the protocol changes between versions.
echo "Checking Playwright version from \"${workspace}\"..."
# shellcheck disable=SC2029 # This is intended to expand client-side.
playwright_version="$(ssh "coder.${workspace}" "cat '${coder_repo}'/site/pnpm-lock.yaml | grep '^ /@playwright/test@' | cut -d '@' -f 3 | tr -d ':'")"

echo "Found Playwright version ${playwright_version}..."

# Let's store it in cache because, why not, this is ephemeral.
dest=~/.cache/coder-remote-playwright
echo "Initializing Playwright server in ${dest}..."
mkdir -p "${dest}"
cd "${dest}"
echo '{"dependencies":{"@playwright/test":"'"${playwright_version}"'"}}' >package.json
cat <<-EOF >server.mjs
import { chromium } from "@playwright/test";

const server = await chromium.launchServer({ headless: false });
console.log(server.wsEndpoint());
EOF

npm_cmd=npm
if command -v pnpm >/dev/null; then
npm_cmd=pnpm
fi
echo "Running \"${npm_cmd} install\" to ensure local and remote are up-to-date..."
"${npm_cmd}" install

echo "Running \"${npm_cmd} exec playwright install\" for browser binaries..."
"${npm_cmd}" exec playwright install

playwright_out="$(mktemp -t playwright_server_out.XXXXXX)"

rm "${playwright_out}"
mkfifo "${playwright_out}"
exec 3<>"${playwright_out}"

echo "Starting Playwright server..."
${npm_cmd} exec node server.mjs 1>&3 &
playwright_pid=$!

trap '
kill -INT ${playwright_pid}
exec 3>&-
rm "${playwright_out}"
wait ${playwright_pid}
' EXIT

echo "Waiting for Playwright to start..."
read -r ws_endpoint <&3
if [[ ${ws_endpoint} != ws://* ]]; then
echo "Playwright failed to start."
echo "${ws_endpoint}"
cat "${playwright_out}"
exit 1
fi
echo "Playwright started at ${ws_endpoint}"

ws_port=${ws_endpoint##*:}
ws_port=${ws_port%/*}

echo
echo "Starting SSH tunnel, run test via \"pnpm run playwright:test\"..."
# shellcheck disable=SC2029 # This is intended to expand client-side.
ssh -t -R "${ws_port}:127.0.0.1:${ws_port}" -L "${port}:127.0.0.1:${port}" coder."${workspace}" "export CODER_E2E_PORT='${port}'; export CODER_E2E_WS_ENDPOINT='${ws_endpoint}'; [[ -d '${coder_repo}/site' ]] && cd '${coder_repo}/site'; exec \"\$(grep \"\${USER}\": /etc/passwd | cut -d: -f7)\" -i -l"
}

main
16 changes: 13 additions & 3 deletions site/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export const port = process.env.CODER_E2E_PORT
? Number(process.env.CODER_E2E_PORT)
: defaultPort;

export const wsEndpoint = process.env.CODER_E2E_WS_ENDPOINT;

const coderMain = path.join(__dirname, "../../enterprise/cmd/coder");

export const STORAGE_STATE = path.join(__dirname, ".auth.json");
Expand Down Expand Up @@ -34,9 +36,17 @@ export default defineConfig({
use: {
baseURL: `http://localhost:${port}`,
video: "retain-on-failure",
launchOptions: {
args: ["--disable-webgl"],
},
...(wsEndpoint
? {
connectOptions: {
wsEndpoint: wsEndpoint,
},
}
: {
launchOptions: {
args: ["--disable-webgl"],
},
}),
},
webServer: {
url: `http://localhost:${port}/api/v2/deployment/config`,
Expand Down