Skip to content
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ The following services are exposed with this addon:

| Service | URL | Notes |
|-------------------------|-----------------------------------|--------------------------------------------------------------------------------------------|
| KasmVNC | https://\<PROJECT>.ddev.site:8444 | Username is your local username. Password is `secret`. |
| KasmVNC | https://\<PROJECT>.ddev.site:8444 | No login required. |
| Playwright Test Reports | https://\<PROJECT>.ddev.site:9324 | This port is changed from the default to not conflict with running Playwright on the host. |

## Viewing test reports
Expand Down
3 changes: 2 additions & 1 deletion config.playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ web_environment:
# We add the sleep so this doesn't error out when not using playwright.
web_extra_daemons:
- name: "kasmvnc"
command: "kasmvncserver -fg || sleep infinity"
# Basic Auth is disabled for both HTTP and the desktop WebSocket.
command: "kasmvncserver -fg -disableBasicAuth || sleep infinity"
directory: /var/www/html
web_extra_exposed_ports:
- name: playwright
Expand Down
26 changes: 16 additions & 10 deletions tests/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ verify_run_playwright() {

mkdir -p "${playwright_dir}/tests"
cp "$DIR"/tests/testdata/phpinfo.spec.ts "${playwright_dir}/tests/phpinfo.spec.ts"
cp "$DIR"/tests/testdata/kasmvnc.spec.ts "${playwright_dir}/tests/kasmvnc.spec.ts"
health_checks

# Both paths expose the same tmpfs: the namespaced path is preferred, while
Expand All @@ -129,12 +130,11 @@ verify_run_playwright() {
assert_success
ddev exec -- rm -f /tmp/ddev-playwright/compatibility-check

# Verify kasmvnc is listening.
curl -s https://"${PROJNAME}".ddev.site:8444/
curl -s --user "$USER":secret https://"${PROJNAME}.ddev.site:8444/"
ddev logs
echo "#" curl -s --user "$USER":secret https://"${PROJNAME}.ddev.site:8444/" >&3
curl -s --user "$USER":secret https://"${PROJNAME}.ddev.site:8444/" | grep -q KasmVNC
# The HTTP client must load without credentials or an authentication challenge.
run curl --fail --silent --show-error --dump-header - "https://${PROJNAME}.ddev.site:8444/"
assert_success
assert_output --partial "KasmVNC"
refute_output --partial "WWW-Authenticate:"

# Verify that browsers have been downloaded.
#
Expand All @@ -160,10 +160,16 @@ verify_run_playwright() {

assert_invariant_layers_precede_browser_install

# Verify we can run an example test. The reporters come from
# playwright.config.ts (line + html); the html one leaves behind a report for
# verify_show_report to serve.
ddev playwright test
# All KasmVNC clients control the same X display. Concurrent clients would
# interleave keyboard input in the focused window, so serialize only this
# desktop-control check. The add-on does not restrict downstream workers.
ddev playwright test kasmvnc.spec.ts --workers=1 --reporter=line

# Application tests have separate browser contexts and can run concurrently.
# Explicitly use three workers so CI exercises parallel application testing
# across Chromium, Firefox and WebKit, even when the fixture's CI default is
# one worker. Keep its line + html reporters for verify_show_report below.
ddev playwright test phpinfo.spec.ts --workers=3

verify_show_report
}
Expand Down
50 changes: 50 additions & 0 deletions tests/testdata/kasmvnc.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { test, expect, chromium } from '@playwright/test';
import { randomUUID } from 'node:crypto';

// Runs in Chromium, Firefox and WebKit, with no httpCredentials configured.
// Loading the HTML alone misses failures in WebSocket auth or RFB negotiation.
// KasmVNC is already running (test.bats checks HTTP readiness), so connection
// setup uses the fixture's normal test and assertion timeouts.
test('KasmVNC connects to the desktop without credentials', async ({ page }) => {
// This headed browser receives input on KasmVNC's X display. Its DOM gives
// us a direct assertion of remote input without desktop screenshot timing.
const desktopBrowser = await chromium.launch({ headless: false, args: ['--kiosk'] });
try {
const desktopPage = await desktopBrowser.newPage();
await desktopPage.setContent(`
<style>
body { margin: 0 }
textarea { width: 100vw; height: 100vh; box-sizing: border-box }
</style>
<textarea autofocus aria-label="Remote input"></textarea>
`);
await desktopPage.bringToFront();
const input = desktopPage.getByRole('textbox');
await input.focus();

const url = new URL(process.env.DDEV_PRIMARY_URL!);
url.port = '8444';
url.searchParams.set('autoconnect', '1');

const response = await page.goto(url.toString());
expect(response?.status()).toBe(200);
expect(response?.headers()['www-authenticate']).toBeUndefined();
await expect(page.locator('html')).toHaveClass(/noVNC_connected/);

// A completed RFB connection must have received the desktop dimensions.
const canvas = page.locator('#noVNC_container canvas').first();
await expect(canvas).toBeVisible();
await expect.poll(() => canvas.evaluate((element: HTMLCanvasElement) =>
element.width > 0 && element.height > 0
)).toBe(true);

// The kiosk window fills the desktop with the textarea. A remote click
// focuses it, then KasmVNC transports the keystrokes to that window.
await canvas.click();
const text = `kasmvnc-${randomUUID()}`;
await page.keyboard.type(text, { delay: 20 });
await expect(input).toHaveValue(text);
} finally {
await desktopBrowser.close();
}
});
4 changes: 3 additions & 1 deletion web-build/disabled.Dockerfile.playwright
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ COPY kasmvnc.yaml xstartup /home/$username/.vnc
RUN chown $username:$username /home/$username/.vnc/*
RUN sudo -u $username touch /home/$username/.vnc/.de-was-selected

RUN sudo -u $username /bin/bash -c 'echo -e "secret\nsecret\n" | kasmvncpasswd -wo -u $USER'
# KasmVNC 1.4.0's launcher requires an account even with -disableBasicAuth.
# This random credential only satisfies that startup check; clients do not use it.
RUN sudo -u $username /bin/bash -c 'password=$(openssl rand -hex 32); printf "%s\n%s\n" "$password" "$password" | kasmvncpasswd -wo -u "$USER"'

# ---------------------------------------------------------------------------
# End of VNC / desktop stack.
Expand Down