setup initial tests

This commit is contained in:
rahulramesha 2024-02-20 16:14:34 +05:30
parent 7628419a26
commit cab93e4c13
9 changed files with 1454 additions and 1273 deletions

10
.gitignore vendored
View File

@ -80,3 +80,13 @@ tmp/
## packages ## packages
dist dist
.temp/ .temp/
## playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

View File

@ -22,6 +22,8 @@
"format": "prettier --write \"**/*.{ts,tsx,md}\"" "format": "prettier --write \"**/*.{ts,tsx,md}\""
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.41.2",
"@types/node": "^20.11.19",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.15",
"eslint-config-custom": "*", "eslint-config-custom": "*",
"postcss": "^8.4.29", "postcss": "^8.4.29",

70
playwright.config.ts Normal file
View File

@ -0,0 +1,70 @@
import { defineConfig, devices } from "@playwright/test";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
require("dotenv").config({ path: "web/.env" });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./web/tests",
/* Run tests in files in parallel */
fullyParallel: false,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* 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",
/* 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:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
baseURL: process.env.PLAYWRIGHT_BASE_URL,
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
//
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://127.0.0.1:3000',
// reuseExistingServer: !process.env.CI,
// },
});

View File

@ -12,7 +12,7 @@ const ToastAlerts = () => {
return ( return (
<div className="pointer-events-none fixed right-5 top-5 z-50 h-full w-80 space-y-5 overflow-hidden"> <div className="pointer-events-none fixed right-5 top-5 z-50 h-full w-80 space-y-5 overflow-hidden">
{alerts.map((alert) => ( {alerts.map((alert) => (
<div className="relative overflow-hidden rounded-md text-white" key={alert.id}> <div className="t-toast-alert relative overflow-hidden rounded-md text-white" key={alert.id}>
<div className="absolute right-1 top-1"> <div className="absolute right-1 top-1">
<button <button
type="button" type="button"
@ -47,8 +47,8 @@ const ToastAlerts = () => {
)} )}
</div> </div>
<div> <div>
<p className="font-semibold">{alert.title}</p> <p className="t-toast-alert-title font-semibold">{alert.title}</p>
{alert.message && <p className="mt-1 text-xs">{alert.message}</p>} {alert.message && <p className="t-toast-alert-message mt-1 text-xs">{alert.message}</p>}
</div> </div>
</div> </div>
</div> </div>

View File

@ -108,14 +108,16 @@ export const WorkspaceSidebarDropdown = observer(() => {
<Menu as="div" className="relative h-full flex-grow truncate text-left"> <Menu as="div" className="relative h-full flex-grow truncate text-left">
{({ open }) => ( {({ open }) => (
<> <>
<Menu.Button className="group/menu-button h-full w-full truncate rounded-md text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:outline-none"> <Menu.Button className="t-workspace-menu group/menu-button h-full w-full truncate rounded-md text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:outline-none">
<div <div
className={`flex items-center gap-x-2 truncate rounded p-1 ${sidebarCollapsed ? "justify-center" : "justify-between" className={`flex items-center gap-x-2 truncate rounded p-1 ${
sidebarCollapsed ? "justify-center" : "justify-between"
}`} }`}
> >
<div className="flex items-center gap-2 truncate"> <div className="flex items-center gap-2 truncate">
<div <div
className={`relative grid h-6 w-6 flex-shrink-0 place-items-center uppercase ${!activeWorkspace?.logo && "rounded bg-custom-primary-500 text-white" className={`relative grid h-6 w-6 flex-shrink-0 place-items-center uppercase ${
!activeWorkspace?.logo && "rounded bg-custom-primary-500 text-white"
}`} }`}
> >
{activeWorkspace?.logo && activeWorkspace.logo !== "" ? ( {activeWorkspace?.logo && activeWorkspace.logo !== "" ? (
@ -136,7 +138,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
</div> </div>
{!sidebarCollapsed && ( {!sidebarCollapsed && (
<ChevronDown <ChevronDown
className={`mx-1 hidden h-4 w-4 flex-shrink-0 group-hover/menu-button:block ${open ? "rotate-180" : "" className={`mx-1 hidden h-4 w-4 flex-shrink-0 group-hover/menu-button:block ${
open ? "rotate-180" : ""
} text-custom-sidebar-text-400 duration-300`} } text-custom-sidebar-text-400 duration-300`}
/> />
)} )}
@ -176,7 +179,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
> >
<div className="flex items-center justify-start gap-2.5 truncate"> <div className="flex items-center justify-start gap-2.5 truncate">
<span <span
className={`relative flex h-6 w-6 flex-shrink-0 items-center justify-center p-2 text-xs uppercase ${!workspace?.logo && "rounded bg-custom-primary-500 text-white" className={`relative flex h-6 w-6 flex-shrink-0 items-center justify-center p-2 text-xs uppercase ${
!workspace?.logo && "rounded bg-custom-primary-500 text-white"
}`} }`}
> >
{workspace?.logo && workspace.logo !== "" ? ( {workspace?.logo && workspace.logo !== "" ? (
@ -190,7 +194,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
)} )}
</span> </span>
<h5 <h5
className={`truncate text-sm font-medium ${workspaceSlug === workspace.slug ? "" : "text-custom-text-200" className={`truncate text-sm font-medium ${
workspaceSlug === workspace.slug ? "" : "text-custom-text-200"
}`} }`}
> >
{workspace.name} {workspace.name}
@ -215,10 +220,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
)} )}
</div> </div>
<div className="flex w-full flex-col items-start justify-start gap-2 px-4 py-2 text-sm"> <div className="flex w-full flex-col items-start justify-start gap-2 px-4 py-2 text-sm">
<Link <Link href="/create-workspace" className="w-full">
href="/create-workspace"
className="w-full"
>
<Menu.Item <Menu.Item
as="div" as="div"
className="flex items-center gap-2 rounded px-2 py-1 text-sm text-custom-sidebar-text-100 hover:bg-custom-sidebar-background-80 font-medium" className="flex items-center gap-2 rounded px-2 py-1 text-sm text-custom-sidebar-text-100 hover:bg-custom-sidebar-background-80 font-medium"

View File

@ -0,0 +1,15 @@
import { test, Page } from "@playwright/test";
export const login = async (page: Page) => {
if (!process.env.PLAYWRIGHT_USERNAME || !process.env.PLAYWRIGHT_PASSWORD) {
test.fail(true, "User name or password not set");
return;
}
await page.goto("/");
await page.getByPlaceholder("name@company.com").click();
await page.getByPlaceholder("name@company.com").fill(process.env.PLAYWRIGHT_USERNAME);
await page.getByRole("button", { name: "Continue" }).click();
await page.getByPlaceholder("Enter password").fill(process.env.PLAYWRIGHT_PASSWORD);
await page.getByRole("button", { name: "Continue" }).click();
};

View File

@ -0,0 +1,46 @@
import { Page, expect } from "@playwright/test";
import { randomUUID } from "crypto";
export const createWorkspace = async (page: Page) => {
await page.locator(".t-workspace-menu").click();
await page.getByRole("link", { name: "Create workspace" }).click();
await page.getByPlaceholder("Enter workspace name...").click();
const uniqueWorkspaceName = randomUUID();
await page.getByPlaceholder("Enter workspace name...").fill(uniqueWorkspaceName);
await page.getByRole("button", { name: "Select organization size" }).click();
await page.getByRole("option", { name: "2-10" }).locator("div").first().click();
await page.getByRole("button", { name: "Create Workspace" }).click();
await assertToast(page, "Success!", "Workspace created successfully.");
await expect(page.getByRole("button", { name: uniqueWorkspaceName })).toBeVisible();
return uniqueWorkspaceName;
};
export const deleteWorkspace = async (page: Page, workspace: string) => {
await page.locator(".t-workspace-menu").click();
await page.getByRole("link", { name: "Settings" }).click();
await page.getByRole("button", { name: "Delete Workspace" }).click();
await page.getByRole("button", { name: "Delete my workspace" }).click();
await page.getByPlaceholder("Workspace name").click();
await page.getByPlaceholder("Workspace name").fill(workspace);
await page.getByPlaceholder("Enter 'delete my workspace'").click();
await page.getByPlaceholder("Enter 'delete my workspace'").fill("delete my workspace");
await page.getByRole("button", { name: "Delete Workspace" }).click();
await assertToast(page, "Success!", "Workspace deleted successfully.");
};
export const assertToast = async (page: Page, title?: string, message?: string) => {
await expect(page.locator(".t-toast-alert")).toBeVisible();
if (title) {
await expect(page.locator(".t-toast-alert-title")).toContainText(title);
}
if (message) {
await expect(page.locator(".t-toast-alert-message ")).toContainText(message);
}
};

View File

@ -0,0 +1,24 @@
import { Page, test } from "@playwright/test";
import { login } from "./helpers/user-helpers";
import { createWorkspace, deleteWorkspace } from "./helpers/workspace-helpers";
test.describe("verify creation and deletion of workspace", () => {
let page: Page;
let workspace: string | undefined;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
await login(page);
});
test("create a workspace", async () => {
workspace = await createWorkspace(page);
});
test("delete a workspace", async () => {
if (!workspace) {
test.fail();
return;
}
await deleteWorkspace(page, workspace);
});
});

2514
yarn.lock

File diff suppressed because it is too large Load Diff