@fake ๊ธฐ๋ฒ์ ์ฌ์ฉํ CSS ํ ์คํธ์ ๊ฐ๋ ฅํจ์ ํ์ํ์ฌ ๋ค์ํ ์ํ์ ์กฐ๊ฑด์ ์๋ฎฌ๋ ์ด์ ํ๊ณ , ๋ธ๋ผ์ฐ์ ์ ์ฅ์น ์ ๋ฐ์ ๊ฑธ์ณ ์ผ๊ด๋๊ณ ์ ๋ขฐํ ์ ์๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๋ณด์ฅํ์ธ์.
CSS @fake: ๊ฒฌ๊ณ ํ ๋์์ธ์ ์ํ ๊ณ ๊ธ ํ ์คํธ ๊ธฐ๋ฒ
ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์์ญ์์ CSS์ ์๊ฐ์ ์ผ๊ด์ฑ๊ณผ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํ๋ ๊ฒ์ ๋ฌด์๋ณด๋ค ์ค์ํฉ๋๋ค. ์ ํต์ ์ธ ํ ์คํธ ๋ฐฉ๋ฒ์ CSS์ ๋์ ์ธ ํน์ฑ๊ณผ ๋ค์ํ ๋ธ๋ผ์ฐ์ , ์ฅ์น, ์ฌ์ฉ์ ์ปจํ ์คํธ์์ ์ํธ์์ฉ์ ๋ค๋ฃฐ ๋ ์ข ์ข ๋ถ์กฑํ ์ ์ด ์์ต๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ "CSS @fake"๋ผ๋ ๊ฐ๋ ์ด ๋ฑ์ฅํฉ๋๋ค. ์ด๋ ํ์ค CSS ๊ธฐ๋ฅ์ ์๋์ง๋ง, ์ด ์ฉ์ด๋ CSS ํ ์คํธ๋ฅผ ์ํ ํต์ ๋๊ณ ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์ ๋ง๋๋ ๊ธฐ๋ฒ๋ค์ ํฌํจํ๋ฉฐ, ๊ฐ๋ฐ์๊ฐ ๋ค์ํ ์ํ, ์กฐ๊ฑด, ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ ๋ฐํ๊ฒ ์๋ฎฌ๋ ์ด์ ํ ์ ์๋๋ก ํฉ๋๋ค.
CSS @fake๋ ๋ฌด์์ธ๊ฐ?
"CSS @fake"๋ @media
๋ @keyframes
์ ๊ฐ์ด ๊ณต์ธ๋ CSS at-rule์ด ์๋๋๋ค. ๋์ , ์ด๋ CSS๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ
์คํธํ๊ธฐ ์ํด ๋ชจ์(mock) ๋๋ ์๋ฎฌ๋ ์ด์
๋ ํ๊ฒฝ์ ๋ง๋๋ ์ ๋ต๋ค์ ๋ชจ์์ ๋ํ๋
๋๋ค. ์ด๋ฌํ ์ ๋ต๋ค์ CSS ์ปดํฌ๋ํธ๋ฅผ ๊ฒฉ๋ฆฌํ๊ณ , ํน์ ์คํ์ผ์ ์ฃผ์
ํ๋ฉฐ, DOM์ ์กฐ์ํ์ฌ ๋ค์ํ ํ๋ฉด ํฌ๊ธฐ, ์ฌ์ฉ์ ์ํธ์์ฉ, ๋๋ ๋ฐ์ดํฐ ์ํ์ ๊ฐ์ ์ฌ๋ฌ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์
ํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค. CSS๋ฅผ ์ํ ํ
์คํธ ๋๋ธ(test double)์ ๋ง๋๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ฉฐ, ์ด๋ฅผ ํตํด ์ธ๋ถ ์์กด์ฑ์ด๋ ๋ณต์กํ ์ค์ ์์ด ํต์ ๋ ์กฐ๊ฑด ํ์์ CSS์ ๋์์ ๊ฒ์ฆํ ์ ์์ต๋๋ค.
CSS @fake ํ ์คํธ๊ฐ ์ค์ํ ์ด์
CSS๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ ์คํธํ๋ ๊ฒ์ ์ฌ๋ฌ ๊ฐ์ง ์ด์ ๋ก ๋งค์ฐ ์ค์ํฉ๋๋ค:
- ์๊ฐ์ ์ผ๊ด์ฑ: UI๊ฐ ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ , ์ด์ ์ฒด์ , ์ฅ์น์์ ์ผ๊ด๋๊ฒ ๋ณด์ด๋๋ก ๋ณด์ฅํฉ๋๋ค. ๋ ๋๋ง ์์ง์ ์ฐจ์ด๋ ๋ฏธ๋ฌํ์ง๋ง ๋์ ๋๋ ์ฐจ์ด๋ฅผ ์ ๋ฐํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
- ๋ฐ์์ฑ: ๋ฐ์ํ ๋์์ธ์ด ๋ค์ํ ํ๋ฉด ํฌ๊ธฐ์ ๋ฐฉํฅ์ ๋ง๊ฒ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ํ๋์ง ๊ฒ์ฆํฉ๋๋ค. ๋ฏธ๋์ด ์ฟผ๋ฆฌ์ ์ ์ฐํ ๋ ์ด์์์ ํ ์คํธํ๋ ๊ฒ์ ๋ชจ๋ ์ฅ์น์์ ์ํํ ๊ฒฝํ์ ๋ง๋๋ ๋ฐ ํ์์ ์ ๋๋ค.
- ์ ๊ทผ์ฑ: CSS๊ฐ ์ ๊ทผ์ฑ ๊ฐ์ด๋๋ผ์ธ์ ์ค์ํ๋์ง ํ์ธํ์ฌ ์ฅ์ ๊ฐ ์๋ ์ฌ๋๋ค๋ ์น์ฌ์ดํธ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์์ ๋๋น, ํฌ์ปค์ค ์ํ, ์๋งจํฑ ๋งํฌ์ ํ ์คํธ๊ฐ ํฌํจ๋ฉ๋๋ค.
- ์ ์ง๋ณด์์ฑ: CSS ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์ ์ง๋ณด์ํ๊ณ ๋ฆฌํฉํ ๋งํ ์ ์๊ฒ ๋ง๋ญ๋๋ค. ํ ์คํธ ์ค์ํธ๊ฐ ์์ผ๋ฉด ์๋์น ์์ ์๊ฐ์ ํ๊ท๋ฅผ ๋์ ํ์ง ์๊ณ ์์ ์๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
- ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ: ํ๋ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์์๋ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค. CSS @fake๋ ๊ฐ ์ปดํฌ๋ํธ์ CSS๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ๊ณผ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ ์ ์๋ ๊ฒฉ๋ฆฌ๋ ์ปดํฌ๋ํธ ํ ์คํธ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ์ฌ ๋ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ๋ง๋ญ๋๋ค.
CSS @fake ๊ตฌํ ๊ธฐ๋ฒ
CSS @fake ํ ์คํธ๋ฅผ ๊ตฌํํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ๋ช ๊ฐ์ง ๊ธฐ๋ฒ์ด ์์ต๋๋ค. ๊ฐ ๊ธฐ๋ฒ์๋ ์ฅ๋จ์ ์ด ์์ผ๋ฏ๋ก, ํ์์ ๊ธฐ์กด ํ ์คํธ ์ธํ๋ผ์ ๊ฐ์ฅ ์ ํฉํ ๊ฒ์ ์ ํํ์ธ์.
1. iFrame์ ์ฌ์ฉํ CSS ๊ฒฉ๋ฆฌ
CSS๋ฅผ ๊ฒฉ๋ฆฌํ๋ ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ ์ค ํ๋๋ ์ปดํฌ๋ํธ๋ UI ์์๋ฅผ iFrame ๋ด์ ์ฝ์ ํ๋ ๊ฒ์ ๋๋ค. iFrame์ CSS๊ฐ ์ฃผ๋ณ ํ์ด์ง๋ก ์ ์ถ๋๊ฑฐ๋ ์ํฅ์ ๋ฐ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ์๋๋ฐ์ค ํ๊ฒฝ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด CSS ํ๊ฒฝ์ ์ ๋ฐํ๊ฒ ์ ์ดํ๊ณ ์ปดํฌ๋ํธ๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ ํ ์คํธํ ์ ์์ต๋๋ค.
์์:
iFrame์ด ์๋ HTML ํ์ผ ์์ฑ:
<!DOCTYPE html>
<html>
<head>
<title>iFrame CSS Isolation Test</title>
</head>
<body>
<iframe src="component.html" width="400" height="300"></iframe>
</body>
</html>
๊ทธ๋ฐ ๋ค์ CSS์ ์ปดํฌ๋ํธ๊ฐ ํฌํจ๋ `component.html` ์์ฑ:
<!DOCTYPE html>
<html>
<head>
<title>Component</title>
<style>
.my-component {
background-color: #f0f0f0;
padding: 20px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="my-component">This is my isolated component.</div>
</body>
</html>
๊ทธ๋ฐ ๋ค์ Jest๋ Mocha์ ๊ฐ์ ํ ์คํธ ํ๋ ์์ํฌ์ Puppeteer๋ Playwright์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ iFrame๊ณผ ์ํธ์์ฉํ๊ณ ์ปดํฌ๋ํธ์ CSS ์์ฑ์ ๊ฒ์ฆํ ์ ์์ต๋๋ค.
์ฅ์ :
- ๊ตฌํ์ด ๊ฐ๋จํฉ๋๋ค.
- ๊ฐ๋ ฅํ CSS ๊ฒฉ๋ฆฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋จ์ :
- ์ฌ๋ฌ iFrame์ ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ฒ๊ฑฐ๋ก์ธ ์ ์์ต๋๋ค.
- ํ ์คํธ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ iFrame๊ณผ ์ํธ์์ฉํ๋ ๊ฒ์ด ์ฝ๊ฐ ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
2. ํ ์คํ ๋ชฉ(Mock)์ ์ด์ฉํ CSS-in-JS
Styled Components, Emotion, ๋๋ JSS์ ๊ฐ์ CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด, ๋ชจํน ๊ธฐ๋ฒ์ ํ์ฉํ์ฌ ํ ์คํธ ์ค์ CSS ํ๊ฒฝ์ ์ ์ดํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ผ๋ฐ์ ์ผ๋ก ํ ์คํธ ๋ชฉ์ ์ผ๋ก ์คํ์ผ์ ์ฌ์ ์ํ๊ฑฐ๋ ์ฌ์ฉ์ ์ ์ ํ ๋ง๋ฅผ ์ฃผ์ ํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค.
์์ (Styled Components์ Jest ์ฌ์ฉ):
์ปดํฌ๋ํธ:
import styled from 'styled-components';
const MyButton = styled.button`
background-color: ${props => props.primary ? 'blue' : 'gray'};
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
`;
export default MyButton;
ํ ์คํธ:
import React from 'react';
import { render } from '@testing-library/react';
import MyButton from './MyButton';
import { ThemeProvider } from 'styled-components';
describe('MyButton', () => {
it('should render with primary color when primary prop is true', () => {
const { getByText } = render(
<ThemeProvider theme={{}}>
<MyButton primary>Click Me</MyButton>
</ThemeProvider>
);
const button = getByText('Click Me');
expect(button).toHaveStyleRule('background-color', 'blue');
});
it('should render with gray color when primary prop is false', () => {
const { getByText } = render(
<ThemeProvider theme={{}}>
<MyButton>Click Me</MyButton>
</ThemeProvider>
);
const button = getByText('Click Me');
expect(button).toHaveStyleRule('background-color', 'gray');
});
});
์ด ์์ ์์๋ Jest์ `@testing-library/react`๋ฅผ ์ฌ์ฉํ์ฌ `MyButton` ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ `jest-styled-components`์ `toHaveStyleRule`์ ์ฌ์ฉํ์ฌ `primary` prop์ ๋ฐ๋ผ ๋ฒํผ์ด ์ฌ๋ฐ๋ฅธ ๋ฐฐ๊ฒฝ์์ ๊ฐ๋์ง ํ์ธํฉ๋๋ค. `ThemeProvider`๋ ํ ์คํธ๋ฅผ ์ํ ์ผ๊ด๋ ํ ๋ง ์ปจํ ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ฅ์ :
- CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ํํ๊ฒ ํตํฉ๋ฉ๋๋ค.
- ์คํ์ผ์ ๋ชจํน๊ณผ ์ฌ์ ์๊ฐ ์ฉ์ดํฉ๋๋ค.
- ์ปดํฌ๋ํธ ์์ค์ CSS ํ ์คํธ๊ฐ ์์ฐ์ค๋ฌ์์ง๋๋ค.
๋จ์ :
- CSS-in-JS ์ ๊ทผ ๋ฐฉ์์ ์ฑํํด์ผ ํฉ๋๋ค.
- ๋ชจํน ๊ธฐ๋ฒ์ ์ต์ํ์ง ์์ ๊ฒฝ์ฐ ํ ์คํธ ์ค์ ์ด ๋ณต์กํด์ง ์ ์์ต๋๋ค.
3. Shadow DOM
Shadow DOM์ ์ปดํฌ๋ํธ ๋ด์ CSS๋ฅผ ์บก์ํํ์ฌ ์ ์ญ ์ค์ฝํ๋ก ์ ์ถ๋๊ฑฐ๋ ์ธ๋ถ ์คํ์ผ์ ์ํฅ์ ๋ฐ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๊ฒฉ๋ฆฌ๋ ํ ์คํธ ํ๊ฒฝ์ ๋ง๋๋ ๋ฐ ์ด์์ ์ ๋๋ค. ์ฌ์ฉ์ ์ ์ ์์(custom elements)์ Shadow DOM์ ์ฌ์ฉํ์ฌ ์บก์ํ๋ CSS๋ฅผ ๊ฐ์ง ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ , ํด๋น ์ปดํฌ๋ํธ๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ ํ ์คํธํ ์ ์์ต๋๋ค.
์์:
<!DOCTYPE html>
<html>
<head>
<title>Shadow DOM CSS Isolation</title>
</head>
<body>
<custom-element></custom-element>
<script>
class CustomElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const wrapper = document.createElement('div');
wrapper.setAttribute('class', 'wrapper');
const style = document.createElement('style');
style.textContent = `
.wrapper {
background-color: lightblue;
padding: 20px;
}
`;
wrapper.textContent = 'Hello, Shadow DOM!';
shadow.appendChild(style);
shadow.appendChild(wrapper);
}
}
customElements.define('custom-element', CustomElement);
</script>
</body>
</html>
์ด ์์ ์์ `.wrapper` ํด๋์ค์ ๋ํ CSS๋ `custom-element`์ Shadow DOM ๋ด์ ์บก์ํ๋ฉ๋๋ค. ์ฌ์ฉ์ ์ ์ ์์ ์ธ๋ถ์์ ์ ์๋ ์คํ์ผ์ Shadow DOM ๋ด๋ถ์ ์คํ์ผ์ ์ํฅ์ ๋ฏธ์น์ง ์์ ๊ฒฉ๋ฆฌ๋ฅผ ๋ณด์ฅํฉ๋๋ค.
์ฅ์ :
- ๊ฐ๋ ฅํ CSS ์บก์ํ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ค์ดํฐ๋ธ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฅ์ ๋๋ค.
- ๊ฒฉ๋ฆฌ๋ ์คํ์ผ๋ง์ผ๋ก ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
๋จ์ :
- ์ฌ์ฉ์ ์ ์ ์์์ Shadow DOM์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- iFrame์ ๋นํด ์ค์ ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
- ๊ตฌํ ๋ธ๋ผ์ฐ์ ์์๋ ํด๋ฆฌํ(polyfill)์ด ํ์ํ ์ ์์ต๋๋ค.
4. CSS ๋ณ์(์ฌ์ฉ์ ์ ์ ์์ฑ) ๋ชจํน
CSS ๋ณ์(์ฌ์ฉ์ ์ ์ ์์ฑ)๋ฅผ ๊ด๋ฒ์ํ๊ฒ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด, ํ ์คํธ ์ค์ ์ด๋ฅผ ๋ชจํนํ์ฌ ๋ค๋ฅธ ํ ๋ง๋ ๊ตฌ์ฑ์ ์๋ฎฌ๋ ์ด์ ํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ปดํฌ๋ํธ๊ฐ ๊ธฐ๋ณธ ๋์์ธ ์์คํ ์ ๋ณ๊ฒฝ์ ์ด๋ป๊ฒ ๋ฐ์ํ๋์ง ํ ์คํธํ ์ ์์ต๋๋ค.
์์:
:root {
--primary-color: blue;
}
.my-component {
background-color: var(--primary-color);
color: white;
padding: 10px;
}
ํ ์คํธ์์ JavaScript๋ฅผ ์ฌ์ฉํ์ฌ `--primary-color` ๋ณ์๋ฅผ ์ฌ์ ์ํ ์ ์์ต๋๋ค:
document.documentElement.style.setProperty('--primary-color', 'red');
์ด๋ ๊ฒ ํ๋ฉด ํ ์คํธ ์ค์ `.my-component`์ ๋ฐฐ๊ฒฝ์์ด ๋นจ๊ฐ์์ผ๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ํ ์คํธ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ๊ฐ ์์๋ ๋ฐฐ๊ฒฝ์์ ๊ฐ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์ฅ์ :
- ์ด๋ฏธ CSS ๋ณ์๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ๊ตฌํ์ด ๊ฐ๋จํฉ๋๋ค.
- ํ ๋ง ๊ด๋ จ ์คํ์ผ์ ๋ชจํน์ด ์ฉ์ดํฉ๋๋ค.
๋จ์ :
- CSS ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ง ์ ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
- ๋ณต์กํ CSS ์ํธ์์ฉ์ ํ ์คํธํ๋ ๋ฐ๋ ๋ ํจ๊ณผ์ ์ผ ์ ์์ต๋๋ค.
5. ์๊ฐ์ ํ๊ท ํ ์คํธ
์๊ฐ์ ํ๊ท ํ ์คํธ๋ ๊ฐ๋ฐ์ ์ฌ๋ฌ ๋จ๊ณ์์ UI ์ปดํฌ๋ํธ์ ์คํฌ๋ฆฐ์ท์ ์ฐ์ด ๊ธฐ์ค ์ด๋ฏธ์ง์ ๋น๊ตํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์๊ฐ์ ์ฐจ์ด๊ฐ ์์ผ๋ฉด ํ ์คํธ๊ฐ ์คํจํ์ฌ ์ ์ฌ์ ์ธ ํ๊ท๋ฅผ ๋ํ๋ ๋๋ค. ์ด๋ CSS ์์ ์ผ๋ก ์ธํ ์๋์น ์์ ์๊ฐ์ ๋ณํ๋ฅผ ๊ฐ์งํ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฒ์ ๋๋ค.
๋๊ตฌ:
- Percy: CI/CD ํ์ดํ๋ผ์ธ๊ณผ ํตํฉ๋๋ ์ธ๊ธฐ ์๋ ์๊ฐ์ ํ๊ท ํ ์คํธ ์๋น์ค์ ๋๋ค.
- Chromatic: Storybook ์ปดํฌ๋ํธ ํ ์คํธ๋ฅผ ์ํด ํน๋ณํ ์ค๊ณ๋ ๋๊ตฌ์ ๋๋ค.
- BackstopJS: ๋ค์ํ ํ ์คํธ ํ๋ ์์ํฌ์ ํจ๊ป ์ฌ์ฉํ ์ ์๋ ์คํ์์ค ์๊ฐ์ ํ๊ท ํ ์คํธ ๋๊ตฌ์ ๋๋ค.
- Applitools: AI ๊ธฐ๋ฐ ์๊ฐ์ ํ ์คํธ ๋ฐ ๋ชจ๋ํฐ๋ง ํ๋ซํผ์ ๋๋ค.
์์ (BackstopJS ์ฌ์ฉ):
- BackstopJS ์ค์น:
npm install -g backstopjs
- BackstopJS ์ด๊ธฐํ:
backstop init
- BackstopJS ๊ตฌ์ฑ (backstop.json)ํ์ฌ ํ ์คํธ ์๋๋ฆฌ์ค์ ๋ทฐํฌํธ ์ ์.
- ํ
์คํธ ์คํ:
backstop test
- ๋ณ๊ฒฝ ์ฌํญ ์น์ธ:
backstop approve
์ฅ์ :
- ๋ค๋ฅธ ํ ์คํธ ๋ฐฉ๋ฒ์ผ๋ก๋ ๋์น ์ ์๋ ๋ฏธ๋ฌํ ์๊ฐ์ ํ๊ท๋ฅผ ์ก์๋ ๋๋ค.
- UI์ ํฌ๊ด์ ์ธ ์๊ฐ์ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋จ์ :
- ๋ ๋๋ง์ ๋ฏธ์ธํ ๋ณํ์ ๋ฏผ๊ฐํ ์ ์์ต๋๋ค.
- ๊ธฐ์ค ์ด๋ฏธ์ง๋ฅผ ์ ์ง ๊ด๋ฆฌํด์ผ ํฉ๋๋ค.
- ๋ค๋ฅธ ํ ์คํธ ๋ฐฉ๋ฒ๋ณด๋ค ๋๋ฆด ์ ์์ต๋๋ค.
CSS @fake ํ ์คํธ๋ฅผ ์ํฌํ๋ก์ฐ์ ํตํฉํ๊ธฐ
CSS @fake ํ ์คํธ๋ฅผ ์ํฌํ๋ก์ฐ์ ํจ๊ณผ์ ์ผ๋ก ํตํฉํ๋ ค๋ฉด ๋ค์์ ๊ณ ๋ คํ์ธ์:
- ์ฌ๋ฐ๋ฅธ ๋๊ตฌ ์ ํ: ๊ธฐ์กด ๊ธฐ์ ์คํ ๋ฐ ํ๋ก์ ํธ ์๊ตฌ ์ฌํญ์ ๋ง๋ ํ ์คํธ ํ๋ ์์ํฌ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๋๊ตฌ๋ฅผ ์ ํํ์ธ์.
- ํ ์คํธ ์๋ํ: CSS ํ ์คํธ๋ฅผ CI/CD ํ์ดํ๋ผ์ธ์ ํตํฉํ์ฌ ๋ชจ๋ ์ฝ๋ ๋ณ๊ฒฝ ์ ์๋์ผ๋ก ์คํ๋๋๋ก ํ์ธ์.
- ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ ํ ์คํธ ์์ฑ: ํ ์คํธ๊ฐ ์ดํดํ๊ณ ์ ์งํ๊ธฐ ์ฝ๋๋ก ๋ง๋์ธ์. ๊ฐ ํ ์คํธ์ ๋ชฉ์ ์ ์ค๋ช ํ๊ธฐ ์ํด ์์ ์ ์ธ ์ด๋ฆ๊ณผ ์ฃผ์์ ์ฌ์ฉํ์ธ์.
- ์ค์ํ ์ปดํฌ๋ํธ์ ์ง์ค: ๋ด๋น๊ฒ์ด์ ๋ฉ๋ด, ํผ, ๋ฐ์ดํฐ ๋์คํ๋ ์ด์ ๊ฐ์ UI์ ๊ฐ์ฅ ์ค์ํ ์ปดํฌ๋ํธ ํ ์คํธ๋ฅผ ์ฐ์ ์ํ์ธ์.
- ๋ค์ํ ์ํ์ ์กฐ๊ฑด ํ ์คํธ: ๋ค์ํ ์ฌ์ฉ์ ์ํธ์์ฉ, ํ๋ฉด ํฌ๊ธฐ, ๋ฐ์ดํฐ ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ์ฌ ๋ชจ๋ ์๋๋ฆฌ์ค์์ CSS๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ํ์ธํ์ธ์.
- ๋์์ธ ์์คํ ์ฌ์ฉ: ๋๊ท๋ชจ ํ๋ก์ ํธ์์ ์์ ํ๋ ๊ฒฝ์ฐ ์ผ๊ด์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๊ธฐ ์ํด ๋์์ธ ์์คํ ์ฌ์ฉ์ ๊ณ ๋ คํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด CSS๋ฅผ ํ ์คํธํ๊ณ ์ ์ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ ์ฌ์์ง๋๋ค.
- ๊ธฐ์ค์ ์ค์ : ์๊ฐ์ ํ๊ท ํ ์คํธ๋ฅผ ์ํด ๋น๊ตํ ์น์ธ๋ ์ด๋ฏธ์ง์ ๋ช ํํ ๊ธฐ์ค์ ์ ์ค์ ํ์ธ์.
ํ ์คํธ ๊ฐ๋ฅํ CSS ์์ฑ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
ํ ์คํธ ๊ฐ๋ฅํ CSS๋ฅผ ์์ฑํ๋ ๊ฒ์ CSS @fake ๊ธฐ๋ฒ์ ํจ๊ณผ์ ์ผ๋ก ๋ง๋๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ธ์:
- CSS๋ฅผ ๋ชจ๋ํํ์ฌ ์ ์ง: CSS๋ฅผ ์๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๋ก ๋๋์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ ํ ์คํธํ๊ธฐ๊ฐ ๋ ์ฌ์์ง๋๋ค.
- ์๋งจํฑ ํด๋์ค ์ด๋ฆ ์ฌ์ฉ: ์ธ๊ด๋ณด๋ค๋ ์์์ ๋ชฉ์ ์ ์ค๋ช ํ๋ ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด CSS๋ฅผ ๋ ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๊ณ ํ ์คํธํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
- ์ง๋์น๊ฒ ๊ตฌ์ฒด์ ์ธ ์ ํ์ ํผํ๊ธฐ: ์ง๋์น๊ฒ ๊ตฌ์ฒด์ ์ธ ์ ํ์๋ CSS๋ฅผ ์ฌ์ ์ํ๊ณ ํ ์คํธํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ๊ฐ๋ฅํ ๋๋ง๋ค ๋ ์ผ๋ฐ์ ์ธ ์ ํ์๋ฅผ ์ฌ์ฉํ์ธ์.
- CSS ๋ณ์(์ฌ์ฉ์ ์ ์ ์์ฑ) ์ฌ์ฉ: CSS ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด ํ ์คํธ ์ค์ ์ฝ๊ฒ ์ฌ์ ์ํ ์ ์๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฐ์ ์ ์ํ ์ ์์ต๋๋ค.
- ์ผ๊ด๋ ์ฝ๋ฉ ์คํ์ผ ์ค์: ์ผ๊ด๋ ์ฝ๋ฉ ์คํ์ผ์ CSS๋ฅผ ์ฝ๊ณ , ์ดํดํ๊ณ , ์ ์ง ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
- CSS ๋ฌธ์ํ: ๊ฐ ํด๋์ค, ๋ณ์, ๊ท์น์ ๋ชฉ์ ์ ์ค๋ช ํ๊ธฐ ์ํด CSS ์ฝ๋๋ฅผ ๋ฌธ์ํํ์ธ์.
์ค์ ์ ์ฉ ์ฌ๋ก
CSS @fake ํ ์คํธ๊ฐ ๋ค์ํ ์๋๋ฆฌ์ค์์ ์ด๋ป๊ฒ ์ ์ฉ๋ ์ ์๋์ง ์ค์ ์ฌ๋ก๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
- ๋ฐ์ํ ๋ด๋น๊ฒ์ด์ ๋ฉ๋ด ํ ์คํธ: iFrame์ด๋ Shadow DOM์ ์ฌ์ฉํ์ฌ ๋ด๋น๊ฒ์ด์ ๋ฉ๋ด๋ฅผ ๊ฒฉ๋ฆฌํ ๋ค์ ํ ์คํธ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ํ๋ฉด ํฌ๊ธฐ์ ์ฌ์ฉ์ ์ํธ์์ฉ(์: hover, click)์ ์๋ฎฌ๋ ์ด์ ํ์ฌ ๋ฉ๋ด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
- ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ์๋ ํผ ํ ์คํธ: ๋ชจํน ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ค์ํ ์ ๋ ฅ ๊ฐ์ ์ฃผ์ ํ๊ณ ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ์ฌ ํผ์ด ์ฌ๋ฐ๋ฅธ ์ค๋ฅ ๋ฉ์์ง์ ์คํ์ผ๋ง์ ํ์ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
- ์ ๋ ฌ ๋ฐ ํํฐ๋ง ๊ธฐ๋ฅ์ด ์๋ ๋ฐ์ดํฐ ํ ์ด๋ธ ํ ์คํธ: ๋ชจํน ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ค์ํ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ์ ๊ณตํ๊ณ ์ ๋ ฌ ๋ฐ ํํฐ๋ง ์์ ์ ์๋ฎฌ๋ ์ด์ ํ์ฌ ํ ์ด๋ธ์ด ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ํ๊ณ ์ ๋ ฌ ๋ฐ ํํฐ๋ง ๊ธฐ๋ฅ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
- ๋ค์ํ ํ ๋ง๋ฅผ ๊ฐ์ง ์ปดํฌ๋ํธ ํ ์คํธ: CSS ๋ณ์์ ๋ชจํน ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ค์ํ ํ ๋ง๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ์ปดํฌ๋ํธ๊ฐ ๊ฐ ํ ๋ง์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
- ๊ธ๋ก๋ฒ ์ ์ ์๊ฑฐ๋ ํ๋ซํผ์ ๋ฒํผ ์คํ์ผ์ ๋ํ ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ํธํ์ฑ ๋ณด์ฅ: ๊ธฐ๋ณธ ๋ธ๋ผ์ฐ์ ์คํ์ผ๋ง์ ์ฐจ์ด๋ ์ฌ์ฉ์์ ๋ธ๋๋ ์ธ์์ ํฐ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ์์ ์๊ฐ์ ํ๊ท ํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฒํผ ๋ชจ์(ํจ๋ฉ, ๊ธ๊ผด ๋ ๋๋ง, ํ ๋๋ฆฌ ๋ฐ๊ฒฝ)์ ๋ถ์ผ์น๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๊ท ์ผํ ๋ธ๋๋ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํ ํ๊ฒ CSS ์กฐ์ ์ ํ ์ ์์ต๋๋ค.
- ๊ตญ์ ๋ด์ค ์น์ฌ์ดํธ์ ๋ค์ํ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง์ ๋ํ ํ ์คํธ ์์ ๋๋น ๊ฒ์ฆ: ์ ๊ทผ์ฑ์ ํนํ ๊ธ๋ก๋ฒ ๋ ์๋ฅผ ๋์์ผ๋ก ํ๋ ๋ด์ค ์น์ฌ์ดํธ์์ ์ค์ํฉ๋๋ค. CSS @fake ํ ์คํธ๋ ํ ์คํธ ์์ ๋ค์ ๋ค๋ฅธ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๋ฅผ ์ฃผ์ ํ๊ณ ์๋ํ๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์์ ๋๋น ๋น์จ์ ํ์ธํ์ฌ ์ ํํ ์ด๋ฏธ์ง์ ๊ด๊ณ์์ด ์๊ฐ ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๊ฐ ์ฝํ ์ธ ๋ฅผ ๊ณ์ ์ฝ์ ์ ์๋๋ก ๋ณด์ฅํ๋ ๊ฒ์ ํฌํจํ ์ ์์ต๋๋ค.
CSS ํ ์คํธ์ ๋ฏธ๋
CSS ํ ์คํธ ๋ถ์ผ๋ ๋์์์ด ๋ฐ์ ํ๊ณ ์์ต๋๋ค. CSS ํ ์คํธ๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ค๊ณ ์๊ฐ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํ ์๋ก์ด ๋๊ตฌ์ ๊ธฐ์ ์ด ๋ฑ์ฅํ๊ณ ์์ต๋๋ค. ์ฃผ๋ชฉํด์ผ ํ ๋ช ๊ฐ์ง ํธ๋ ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋ ๋ฐ์ ๋ ์๊ฐ์ ํ๊ท ํ ์คํธ ๋๊ตฌ: AI ๊ธฐ๋ฐ ์๊ฐ์ ํ๊ท ํ ์คํธ ๋๊ตฌ๊ฐ ๋์ฑ ์ ๊ตํด์ ธ ๋ฏธ๋ฌํ ์๊ฐ์ ์ฐจ์ด๋ฅผ ๋ ๋์ ์ ํ๋๋ก ๊ฐ์งํ ์ ์๊ฒ ๋์์ต๋๋ค.
- ๋์์ธ ์์คํ ๊ณผ์ ํตํฉ: ํ ์คํธ ๋๊ตฌ๊ฐ ๋์์ธ ์์คํ ๊ณผ ๋์ฑ ํตํฉ๋์ด ๋๊ท๋ชจ ํ๋ก์ ํธ์์ CSS๋ฅผ ํ ์คํธํ๊ณ ์ ์ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ ์ฌ์์ง๊ณ ์์ต๋๋ค.
- ์ ๊ทผ์ฑ ํ ์คํธ์ ๋ํ ๊ฐ์กฐ ์ฆ๊ฐ: ์กฐ์ง์ด ํฌ์ฉ์ ์ธ ์น์ฌ์ดํธ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค๊ธฐ ์ํด ๋ ธ๋ ฅํจ์ ๋ฐ๋ผ ์ ๊ทผ์ฑ ํ ์คํธ๊ฐ ๋์ฑ ์ค์ํด์ง๊ณ ์์ต๋๋ค.
- ์ปดํฌ๋ํธ ์์ค ํ ์คํธ์ ํ์คํ: ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ์ ๋ถ์์ CSS @fake ๊ธฐ๋ฒ์ ํฌํจํ ๊ฒฌ๊ณ ํ ์ปดํฌ๋ํธ ํ ์คํธ ์ ๋ต์ ํ์๋ก ํฉ๋๋ค.
๊ฒฐ๋ก
CSS @fake ํ ์คํธ๋ CSS์ ์๊ฐ์ ์ผ๊ด์ฑ, ๋ฐ์์ฑ ๋ฐ ์ ๊ทผ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ๋์์ด ๋๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฒ ๋ชจ์์ ๋๋ค. CSS ํ ์คํธ๋ฅผ ์ํ ํต์ ๋๊ณ ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์ ๋ง๋ค์ด ์ค๋ฅ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ๊ณ ์๊ฐ์ ํ๊ท๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค. CSS @fake ํ ์คํธ๋ฅผ ์ํฌํ๋ก์ฐ์ ํตํฉํ๊ณ ํ ์คํธ ๊ฐ๋ฅํ CSS ์์ฑ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ๋ ๊ฒฌ๊ณ ํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค.
ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ด ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ CSS ํ ์คํธ์ ์ค์์ฑ์ ๋์ฑ ์ปค์ง ๊ฒ์ ๋๋ค. CSS @fake ๊ธฐ๋ฒ ๋ฐ ๊ธฐํ ๊ณ ๊ธ ํ ์คํธ ๋ฐฉ๋ฒ์ ์ฑํํจ์ผ๋ก์จ ์๋์ ์์ ๋๊ฐ๊ณ ์ฌ์ฉ์์ ์๊ตฌ๋ฅผ ์ถฉ์กฑํ๋ ๊ณ ํ์ง ์น ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค.