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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ docs/work/

# Playwright
docs/e2e-ui/
e2e/.auth/*.json
playwright-report/
test-results/
.playwright-mcp/
Expand Down
Empty file added e2e/.auth/.gitkeep
Empty file.
8 changes: 8 additions & 0 deletions e2e/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { test as setup } from "@playwright/test";

import { AUTH_FILE, BACKEND_URL } from "./constants";

setup("authenticate", async ({ request }) => {
await request.post(`${BACKEND_URL}/auth/e2e-login`);
await request.storageState({ path: AUTH_FILE });
});
23 changes: 23 additions & 0 deletions e2e/authenticated.auth.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect, test } from "@playwright/test";

import { E2E_USER_DISPLAY_NAME } from "./constants";

test.describe("로그인 상태 테스트", () => {
test("로그인 후 사용자 정보가 헤더에 표시됨", async ({ page }) => {
await page.goto("/");

const userMenu = page.getByRole("button", { name: new RegExp(E2E_USER_DISPLAY_NAME) });
await expect(userMenu).toBeVisible();
});

test("로그인 후 컨텐츠 상세에서 보상 수정 버튼이 활성화됨", async ({ page }) => {
await page.goto("/");

const firstRow = page.locator("table tbody tr").first();
await firstRow.click();

const settingsButton = page.getByTestId("content-reward-section").getByRole("button");
await expect(settingsButton).toBeVisible();
await expect(settingsButton).toBeEnabled();
});
});
4 changes: 4 additions & 0 deletions e2e/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const AUTH_FILE = "e2e/.auth/user.json";
export const BACKEND_URL = "http://localhost:3001";
export const E2E_USER_DISPLAY_NAME = "E2E Test User";
export const FRONTEND_URL = "http://localhost:3000";
6 changes: 2 additions & 4 deletions e2e/home.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect, test } from "@playwright/test";

test.describe("홈 페이지", () => {
test.use({ storageState: { cookies: [], origins: [] } }); // 비로그인 상태로 테스트

test.beforeEach(async ({ page }) => {
await page.goto("/");
});
Expand All @@ -10,18 +12,14 @@ test.describe("홈 페이지", () => {
});

test("백엔드에서 골드 환율을 표시함", async ({ page }) => {
// 골드 환율 설정 버튼이 표시되는지 확인 (백엔드 API 호출 필요)
const exchangeRateButton = page.getByRole("button", {
name: /골드 환율 설정/,
});
await expect(exchangeRateButton).toBeVisible();

// 환율 정보가 포함되어 있는지 확인 (예: "500:650")
await expect(exchangeRateButton).toContainText(/\d+:\d+/);
});

test("백엔드에서 컨텐츠 시급 목록을 로드함", async ({ page }) => {
// 테이블 행이 존재하는지 확인 (백엔드에서 데이터를 받아옴)
const tableRows = page.locator("table tbody tr");
await expect(tableRows).not.toHaveCount(0);
});
Expand Down
18 changes: 16 additions & 2 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig, devices } from "@playwright/test";

const FRONTEND_URL = "http://localhost:3000";
const BACKEND_URL = "http://localhost:3001";
import { AUTH_FILE, BACKEND_URL, FRONTEND_URL } from "./e2e/constants";

const WEBSERVER_TIMEOUT_MS = 3 * 60 * 1000;

export default defineConfig({
Expand All @@ -19,8 +19,22 @@ export default defineConfig({
video: process.env.CI ? "retain-on-failure" : "on",
},
projects: [
{
name: "setup",
testMatch: /.*\.setup\.ts/,
},
{
name: "chromium",
dependencies: ["setup"],
testMatch: /.*\.auth\.spec\.ts/,
use: {
...devices["Desktop Chrome"],
storageState: AUTH_FILE,
},
},
{
name: "chromium-no-auth",
testIgnore: /.*\.auth\.spec\.ts/,
use: { ...devices["Desktop Chrome"] },
},
],
Expand Down
32 changes: 31 additions & 1 deletion src/backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Controller,
ForbiddenException,
Get,
HttpException,
HttpStatus,
Expand All @@ -10,11 +11,23 @@ import {
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { AuthGuard } from "@nestjs/passport";
import { AuthProvider } from "@prisma/client";
import { Request, Response } from "express";
import { PrismaService } from "src/prisma";

const E2E_TEST_USER = {
displayName: "E2E Test User",
email: "e2e-test@example.com",
provider: AuthProvider.GOOGLE,
refId: "e2e-test-user-ref-id",
};

@Controller("auth")
export class AuthController {
constructor(private configService: ConfigService) {}
constructor(
private configService: ConfigService,
private prisma: PrismaService
) {}

@Get("check")
async check(@Req() req: Request) {
Expand All @@ -37,6 +50,23 @@ export class AuthController {
return req.user;
}

@Post("e2e-login")
async e2eLogin(@Req() req: Request) {
if (process.env.NODE_ENV === "production") {
throw new ForbiddenException("E2E login is disabled in production");
}

const user = await this.prisma.user.upsert({
create: E2E_TEST_USER,
update: {},
where: { refId: E2E_TEST_USER.refId },
});

req.session["passport"] = { user };

return user;
}

@Get("google/callback")
@UseGuards(AuthGuard("google"))
async googleCallback(@Req() req: Request, @Res() res: Response) {
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/src/components/section/section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import { ReactNode } from "react";
import { ErrorBoundary } from "~/components/error";

export type SectionProps = Omit<BoxProps, "title"> & {
testId?: string;
title?: ReactNode;
};

export const Section = ({ children, title, ...props }: SectionProps) => {
export const Section = ({ children, testId, title, ...props }: SectionProps) => {
return (
<Box
bg="bg.container"
border="1px solid"
borderColor="border.subtle"
borderRadius="md"
boxShadow="md"
data-testid={testId}
p={{ base: 2, md: 4 }}
w="100%"
{...props}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ContentRewardSection = ({

return (
<Section
testId="content-reward-section"
title={
<Flex alignItems="center" gap={2}>
<Text>보상 정보</Text>
Expand Down
Loading