Skip to content
Open
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
52 changes: 51 additions & 1 deletion packages/e2e-react/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
# E2E EmbeddedChat setup
# E2E EmbeddedChat Tests

End-to-end tests using Playwright for the EmbeddedChat React package. Tests focus on UI stability and deterministic flows without external service dependencies.

## Setup

### Install system dependencies (Linux)
```bash
sudo yarn playwright install-deps
```

### Install Playwright browsers
```bash
cd packages/e2e-react
npx playwright install chromium
```

## Run Tests

### Local
```bash
yarn workspace e2e-react test
```

### Watch mode
```bash
yarn workspace e2e-react test --watch
```

### Debug UI
```bash
yarn workspace e2e-react test --debug
```

### View HTML report
```bash
yarn workspace e2e-react show-report
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README instructs running yarn workspace e2e-react show-report, but this workspace’s package.json doesn’t define a show-report script. Either add a show-report script (e.g., invoking playwright show-report) or update the docs to use npx playwright show-report / yarn playwright show-report so the command works.

Suggested change
yarn workspace e2e-react show-report
npx playwright show-report

Copilot uses AI. Check for mistakes.
```

## Test Coverage

- **renders unauthenticated chat state** β€” Verifies EmbeddedChat loads with login prompt
- **opens login modal from join button** β€” Ensures JOIN button opens password auth modal
- **shows required field validation for empty login submit** β€” Tests form validation without auth service

## Configuration

- Base URL: `http://127.0.0.1:5173` (dev server)
- Host (RC server): Configurable via `VITE_RC_HOST` env var, defaults to `http://127.0.0.1:3000`
- CI retries: 2 (enabled on CI only)
- Failure artifacts: Screenshots + traces automatically collected
7 changes: 5 additions & 2 deletions packages/e2e-react/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ export default defineConfig({
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
reporter: process.env.CI
? [['github'], ['html', { open: 'never' }]]
: [['list'], ['html', { open: 'never' }]],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'http://127.0.0.1:5173',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above trace is now inaccurate: the config uses trace: 'retain-on-failure' (not β€œwhen retrying the failed test”). Update the comment to reflect the current behavior so future changes don’t misinterpret what artifacts are collected.

Suggested change
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
/* Collect and retain trace on test failure. See https://playwright.dev/docs/trace-viewer */

Copilot uses AI. Check for mistakes.
trace: 'on-first-retry',
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
},

/* Configure projects for major browsers */
Expand Down
4 changes: 3 additions & 1 deletion packages/e2e-react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
import { EmbeddedChat } from "@embeddedchat/react";

function App() {
const host = import.meta.env.VITE_RC_HOST || "http://127.0.0.1:3000";
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import.meta.env.VITE_RC_HOST will fail TypeScript type-checking unless ImportMetaEnv is augmented (Vite’s default ImportMetaEnv doesn’t declare this key). Add a declaration in src/vite-env.d.ts for readonly VITE_RC_HOST?: string (or access via bracket notation with an explicit cast) so yarn build (which runs tsc) stays green.

Suggested change
const host = import.meta.env.VITE_RC_HOST || "http://127.0.0.1:3000";
const host =
(import.meta.env as { VITE_RC_HOST?: string }).VITE_RC_HOST ||
"http://127.0.0.1:3000";

Copilot uses AI. Check for mistakes.

return (
<EmbeddedChat
host="https://demo.qa.rocket.chat/"
host={host}
roomId="66ccc4f1e050428c76256939"
/>
);
Expand Down
8 changes: 8 additions & 0 deletions packages/e2e-react/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
/// <reference types="vite/client" />

interface ImportMetaEnv {
readonly VITE_RC_HOST?: string;
}

interface ImportMeta {
readonly env: ImportMetaEnv;
}
26 changes: 20 additions & 6 deletions packages/e2e-react/tests/example.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import { test, expect } from "@playwright/test";

test("EmbeddedChat should render", async ({ page }) => {
test.beforeEach(async ({ page }) => {
await page.goto("/");
});

test("renders unauthenticated chat state", async ({ page }) => {
await expect(page.locator(".ec-embedded-chat")).toBeVisible();
await expect(page.getByRole("heading", { name: "Login to chat" })).toBeVisible();
await expect(page.getByRole("button", { name: "JOIN" })).toBeVisible();
await expect(page.getByPlaceholder("Sign in to chat")).toBeDisabled();
});

test("EmbeddedChat has a title", async ({ page }) => {
await page.goto("/");
await expect(page.locator(".ec-chat-header--channelName")).toHaveText(
"Login to chat"
);
test("opens login modal from join button", async ({ page }) => {
await page.getByRole("button", { name: "JOIN" }).click();

await expect(page.getByRole("heading", { name: "Login" })).toBeVisible();
await expect(page.getByText("Email or username")).toBeVisible();
await expect(page.getByText("Password")).toBeVisible();
});

test("shows required field validation for empty login submit", async ({ page }) => {
await page.getByRole("button", { name: "JOIN" }).click();
await page.getByRole("dialog").getByRole("button", { name: "Login" }).click();

await expect(page.getByText("This field is required")).toHaveCount(2);
});
10 changes: 8 additions & 2 deletions packages/react/src/views/LoginForm/LoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,14 @@ export default function LoginForm() {
}, [userOrEmail, password]);

const handleSubmit = () => {
if (!userOrEmail) setUserOrEmail('');
if (!password) setPassword('');
if (!userOrEmail) {
setUserOrEmail('');
return;
}
if (!password) {
setPassword('');
return;
}
handleLogin(userOrEmail, password);
};
const handleClose = () => {
Expand Down