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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@
tsconfig.tsbuildinfo

# Jest globalConfig file
../globalConfig.json
../globalConfig.json
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
3 changes: 2 additions & 1 deletion client/src/components/bottomNavigator/BottomNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const BottomNavigator = ({
}: BottomNavigatorProps) => {
return (
<div className={bottomNavigatorContainer} {...BottomNavigatorOnBoardingProps}>
{pages.map((page) => (
{pages.map((page, idx) => (
<motion.div
key={page.id}
initial={animation.initial}
Expand All @@ -29,6 +29,7 @@ export const BottomNavigator = ({
key={page.id}
icon={page.icon}
size="md"
testKey={`BottomNavigator-iconButton-${idx}`}
onClick={() => {
handlePageSelect({
pageId: page.id,
Expand Down
4 changes: 3 additions & 1 deletion client/src/components/button/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { iconButtonContainer } from "./IconButton.style";
interface IconButtonProps {
icon: PageIconType | "plus";
size: "sm" | "md";
testKey: string;
onClick?: () => void;
}

export const IconButton = ({ icon, size, onClick }: IconButtonProps) => {
export const IconButton = ({ icon, size, testKey, onClick }: IconButtonProps) => {
const { icon: IconComponent, color: defaultColor }: IconConfig = iconComponents[icon];

return (
<button
data-testid={testKey}
className={iconButtonContainer({ size })}
data-onboarding="page-add-button"
onClick={onClick}
Expand Down
9 changes: 8 additions & 1 deletion client/src/components/button/textButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ import { textButtonContainer } from "./textButton.style";
interface TextButtonProps {
variant?: "primary" | "secondary";
children: React.ReactNode;
testKey: string;
onClick?: () => void;
}

export const TextButton = ({ variant = "primary", children, onClick }: TextButtonProps) => {
export const TextButton = ({
variant = "primary",
children,
testKey,
onClick,
}: TextButtonProps) => {
return (
<button
data-testid={testKey}
className={textButtonContainer({ variant })}
onClick={onClick}
data-onboarding="login-button"
Expand Down
10 changes: 8 additions & 2 deletions client/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,17 @@ export const Modal = ({
<div className={modalContent}>{children}</div>
<div className={buttonContainer}>
{secondaryButtonLabel && (
<TextButton onClick={secondaryButtonOnClick} variant="secondary">
<TextButton
testKey="modalSecondaryButton"
onClick={secondaryButtonOnClick}
variant="secondary"
>
{secondaryButtonLabel}
</TextButton>
)}
<TextButton onClick={primaryButtonOnClick}>{primaryButtonLabel}</TextButton>
<TextButton testKey="modalPrimaryButton" onClick={primaryButtonOnClick}>
{primaryButtonLabel}
</TextButton>
</div>
</motion.div>
</div>
Expand Down
13 changes: 10 additions & 3 deletions client/src/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,14 @@ export const Sidebar = ({

return (
<motion.aside
data-testid="sidebar"
className={sidebarContainer}
initial="open"
animate={isSidebarOpen ? "open" : "closed"}
variants={sidebarVariants}
{...sidebarOnBoardingProps}
>
<div className={sidebarToggleButton} onClick={toggleSidebar}>
<div data-testid="sidebarToggle" className={sidebarToggleButton} onClick={toggleSidebar}>
{isSidebarOpen ? "«" : "»"}
</div>
<motion.div variants={contentVariants}>
Expand All @@ -100,7 +101,7 @@ export const Sidebar = ({
{pages.length === 0 ? (
<div className={placeholderMessage}>+ 버튼을 눌러 페이지를 추가하세요</div>
) : (
pages?.map((item) => (
pages?.map((item, idx) => (
<motion.div
key={item.id}
initial={animation.initial}
Expand All @@ -109,6 +110,7 @@ export const Sidebar = ({
>
<PageItem
{...item}
testKey={`pageItem-${idx}`}
onClick={() => handlePageItemClick(item.id)}
onDelete={() => confirmPageDelete(item)}
handleIconUpdate={handlePageUpdate}
Expand All @@ -118,7 +120,12 @@ export const Sidebar = ({
)}
</motion.nav>
<motion.div className={plusIconBox} variants={contentVariants}>
<IconButton icon="plus" onClick={handleAddPageButtonClick} size="sm" />
<IconButton
testKey="addPageButton"
icon="plus"
onClick={handleAddPageButtonClick}
size="sm"
/>
<AuthButton />
</motion.div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { IconBox } from "./PageIconButton.style";

interface PageIconButtonProps {
type: PageIconType;
testKey: string;
onClick: (e: React.MouseEvent) => void;
}

export const PageIconButton = ({ type, onClick }: PageIconButtonProps) => {
export const PageIconButton = ({ type, testKey, onClick }: PageIconButtonProps) => {
const { icon: IconComponent, color: defaultColor }: IconConfig = iconComponents[type];

return (
<div style={{ position: "relative" }}>
<div data-testid={testKey} style={{ position: "relative" }}>
<div className={IconBox} onClick={(e) => onClick(e)}>
<IconComponent color={defaultColor} size="24px" />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export interface PageIconModalProps {

export const PageIconModal = ({ onClose, onSelect, currentType }: PageIconModalProps) => {
return (
<div className={IconModal} onClick={onClose}>
<div data-testid="iconModal" className={IconModal} onClick={onClose}>
<div className={IconModalContainer} onClick={onClose}>
<button onClick={onClose} className={IconModalClose}>
<button data-testid="iconModalCloseButton" onClick={onClose} className={IconModalClose}>
<RiCloseLine width={16} height={16} />
</button>
<div>
Expand All @@ -39,6 +39,7 @@ export const PageIconModal = ({ onClose, onSelect, currentType }: PageIconModalP

return (
<button
data-testid={`iconModalButton-${iconType}`}
key={iconType}
onClick={(e) => onSelect(e, iconType)}
className={IconButton(isSelected)}
Expand Down
20 changes: 16 additions & 4 deletions client/src/components/sidebar/components/pageItem/PageItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface PageItemProps {
id: string;
title: string;
icon: PageIconType;
testKey: string;
onClick: () => void;
onDelete?: (id: string) => void; // 추가: 삭제 핸들러
handleIconUpdate: (
Expand All @@ -23,6 +24,7 @@ export const PageItem = ({
id,
icon,
title,
testKey,
onClick,
onDelete,
handleIconUpdate,
Expand Down Expand Up @@ -61,10 +63,20 @@ export const PageItem = ({
};

return (
<div className={pageItemContainer} onClick={onClick}>
<PageIconButton type={pageIcon ?? "Docs"} onClick={handleToggleModal} />
<span className={textBox}>{title || "새로운 페이지"}</span>
<span className={`delete_box ${deleteBox}`} onClick={handleDelete}>
<div data-testid={testKey} className={pageItemContainer} onClick={onClick}>
<PageIconButton
testKey={`pageIconButton-${testKey.split("-")[1]}-${pageIcon}`}
type={pageIcon ?? "Docs"}
onClick={handleToggleModal}
/>
<span data-testid={`sidebarTitle-${testKey.split("-")[1]}`} className={textBox}>
{title || "새로운 페이지"}
</span>
<span
data-testid={`pageDeleteButton-${testKey.split("-")[1]}`}
className={`delete_box ${deleteBox}`}
onClick={handleDelete}
>
<CloseIcon width={16} height={16} />
</span>
{isOpen && (
Expand Down
4 changes: 2 additions & 2 deletions client/src/features/auth/AuthButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export const AuthButton = () => {
return (
<div className={container}>
{isLogin ? (
<TextButton onClick={openLogoutModal} variant="secondary">
<TextButton testKey="sidebarLogoutButton" onClick={openLogoutModal} variant="secondary">
로그아웃
</TextButton>
) : (
<TextButton onClick={openAuthModal} variant="secondary">
<TextButton testKey="sidebarLoginButton" onClick={openAuthModal} variant="secondary">
로그인
</TextButton>
)}
Expand Down
10 changes: 8 additions & 2 deletions client/src/features/auth/AuthModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,14 @@ export const AuthModal = ({ isOpen, onClose }: AuthModalProps) => {
isError={getFieldError("password")}
/>
</div>
<div className={errorWrapper}>{error && <p className={errorContainer}>{error}</p>}</div>
<button onClick={toggleMode} className={toggleButton}>
<div className={errorWrapper}>
{error && (
<p data-testid="authErrorMessage" className={errorContainer}>
{error}
</p>
)}
</div>
<button data-testid="toSignUpButton" onClick={toggleMode} className={toggleButton}>
{mode === "login"
? "계정이 없으신가요? 회원가입하기"
: "이미 계정이 있으신가요? 로그인하기"}
Expand Down
17 changes: 13 additions & 4 deletions client/src/features/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ export interface EditorStateProps {
}

interface EditorProps {
testKey: string;
onTitleChange: (title: string, syncWithServer: boolean) => void;
pageId: string;
serializedEditorData: serializedEditorDataProps;
pageTitle: string;
}

export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData }: EditorProps) => {
export const Editor = ({
testKey,
onTitleChange,
pageId,
pageTitle,
serializedEditorData,
}: EditorProps) => {
const {
sendCharInsertOperation,
sendCharDeleteOperation,
Expand Down Expand Up @@ -343,9 +350,10 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
return <div>Loading editor data...</div>;
}
return (
<div className={editorContainer}>
<div data-testid={`editor-${testKey}`} className={editorContainer}>
<div className={editorTitleContainer}>
<input
data-testid={`editorTitle-${testKey}`}
type="text"
placeholder="제목을 입력하세요..."
onChange={handleTitleChange}
Expand All @@ -369,8 +377,9 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
.map((block) => `${block.id.client}-${block.id.clock}`)}
strategy={verticalListSortingStrategy}
>
{editorState.linkedList.spread().map((block) => (
{editorState.linkedList.spread().map((block, idx) => (
<Block
testKey={`block-${idx}`}
key={`${block.id.client}-${block.id.clock}`}
id={`${block.id.client}-${block.id.clock}`}
block={block}
Expand All @@ -397,7 +406,7 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
</SortableContext>
</DndContext>
{editorState.linkedList.spread().length === 0 && (
<div className={addNewBlockButton} onClick={addNewBlock}>
<div data-testId="addNewBlockButton" className={addNewBlockButton} onClick={addNewBlock}>
클릭해서 새로운 블록을 추가하세요
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ElementType } from "@noctaCrdt/Interfaces";
import { iconContainerStyle, iconStyle } from "./IconBlock.style";

interface IconBlockProps {
testKey: string;
type: ElementType;
index: number | undefined;
indent?: number;
Expand All @@ -10,6 +11,7 @@ interface IconBlockProps {
}

export const IconBlock = ({
testKey,
type,
index = 1,
indent = 0,
Expand Down Expand Up @@ -48,5 +50,9 @@ export const IconBlock = ({
const icon = getIcon();
if (!icon) return null;

return <div className={iconContainerStyle}>{icon}</div>;
return (
<div data-testid={testKey} className={iconContainerStyle}>
{icon}
</div>
);
};
6 changes: 5 additions & 1 deletion client/src/features/editor/components/block/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
} from "./Block.style";

interface BlockProps {
testKey: string;
id: string;
block: CRDTBlock;
dragBlockList: string[];
Expand Down Expand Up @@ -70,6 +71,7 @@ interface BlockProps {
}
export const Block: React.FC<BlockProps> = memo(
({
testKey,
id,
block,
dragBlockList,
Expand Down Expand Up @@ -273,7 +275,7 @@ export const Block: React.FC<BlockProps> = memo(
return (
// TODO: eslint 규칙을 수정해야 할까?
// TODO: ol일때 index 순서 처리
<div style={{ position: "relative" }}>
<div data-testid={testKey} style={{ position: "relative" }}>
{showTopIndicator && <Indicator />}
<motion.div
ref={setNodeRef}
Expand All @@ -297,13 +299,15 @@ export const Block: React.FC<BlockProps> = memo(
/>

<IconBlock
testKey="iconBlock"
type={block.type}
index={block.listIndex}
indent={block.indent}
isChecked={block.isChecked}
onCheckboxClick={handleCheckboxClick}
/>
<div
data-testid="contentEditable"
ref={blockRef}
onKeyDown={(e) => handleKeyDown(e, blockRef.current, block)}
onInput={handleInput}
Expand Down
Loading
Loading