ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ ํ•œ๊ณ„ - ๊ตฌ๋งค ํŽ˜์ด์ง€

date
2026-02-04
order
9

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

๊ตฌ๋งค ํŽ˜์ด์ง€์—๋Š” ์„ธ ๊ฐ€์ง€ ์˜์—ญ์ด ์žˆ๋‹ค :

  • <ShippingInformationForm />
    • ๋ฐฐ์†ก ์ •๋ณด ์ž…๋ ฅ
    • API๋ฅผ ํ†ตํ•ด ์ฟ ํฐ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๋ Œ๋”๋ง
    • ๊ฐ ํ•„๋“œ๋ณ„ ์œ ํšจ์„ฑ ๊ฒ€์ฆ
  • <ItemList />
    • ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ์ƒํ’ˆ๊ณผ ๊ฐ€๊ฒฉ ์ •๋ณด ๋…ธ์ถœ
  • <Payment />
    • ์ด ์ƒํ’ˆ ๊ธˆ์•ก, ํ• ์ธ ์ฟ ํฐ, ์ด ๊ฒฐ์ œ ๊ธˆ์•ก ๋“ฑ ๊ฒฐ์ œ ์ •๋ณด๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ๋…ธ์ถœ
    • ๊ฒฐ์ œ ๋ฐฉ๋ฒ• ์„ ํƒ
const { resetCart } = useCartStore(state => pick(state, 'resetCart'));
const { user } = useUserStore(state => pick(state, 'user'));
  //...
const methods = useForm({
    defaultValues: {
      name: user?.name ?? '',
      address: '',
      phone: '',
      requests: '',
      coupon: NO_COUPON_ID,
      payment: 'accountTransfer',
    },
  });
const { handleSubmit } = methods;

return (
  <FormProvider {...methods}>
  //...
  <ShippingInformationForm />
  <ItemList />
  <Payment />
  //...
  <Button
     variant="contained"
      size="large"
      onClick={handleClickPurchase}
  >
    ๊ตฌ๋งคํ•˜๊ธฐ
  </Button>
  </FormProvider>
);

ShippingInformationForm

ShippingInformationForm์€ ๊ฐ ์ž…๋ ฅ์ฐฝ๋งˆ๋‹ค useFormContext()๋กœ FormProvider์˜ ์ปจํ…์ŠคํŠธ์™€ ์—ฐ๋™ํ•˜์—ฌ ์ž…๋ ฅ๊ฐ’ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ํ•œ๋‹ค.

const NameTableRow = () => {
  const {
    register,
    formState: { errors },
  } = useFormContext();

  return (
    //...
          <TextField
            {...register('name', { required: '์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”' })}
            type="input"
            error={!!errors?.name}
            helperText={errors?.name?.message}
            size="small"
            placeholder="์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”"
          />
    //...
  );
};

๊ทธ๋ž˜์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ์ด ์ปจํ…์ŠคํŠธ ํ”„๋กœ๋ฐ”์ด๋” ์ปดํฌ๋„ŒํŠธ๋„ ๋ชจํ‚น์„ ํ•ด์•ผํ•œ๋‹ค.

//ShippingINformationForm.spec.jsx
const TestForm = props => {
  const methods = useForm({
    defaultValues: {
      name: '',
      address: '',
      phone: '',
      requests: '',
      coupon: NO_COUPON_ID,
      ...props,
    },
  });

  return (
    <FormProvider {...methods}>
      <ShippingInformationForm />
      <button type="button" onClick={methods.handleSubmit(() => {})}>
        ํ…Œ์ŠคํŠธ ๋ฒ„ํŠผ
      </button>
    </FormProvider>
  );
};

ItemList

์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ์ƒํ’ˆ๋“ค์˜ ๊ฐœ์ˆ˜์™€ ์ด์•ก์„ ๋ณด์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ ๊ฒ€์ฆํ• ๊ฒŒ ๊ฐ„๋‹จํ•˜๋‹ค. cart ์Šคํ† ์–ด๋งŒ ๋ชจํ‚นํ•ด์„œ ์ƒํ’ˆ ๊ฐœ์ˆ˜์™€ ๊ธˆ์•ก์ด ๋งž๋Š”์ง€๋งŒ ๊ฒ€์ฆํ•˜๋ฉด ๋œ๋‹ค.

//ItemList.spec.jsx
beforeEach(() => {
  mockUseCartStore({
    cart: {
      6: {
        id: 6,
        title: 'Handmade Cotton Fish',
        price: 100,
        description:
  //...
  

Payment

์ด ์ปดํฌ๋„ŒํŠธ๋„ <FormProvider>์˜ ์ปจํ…์ŠคํŠธ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ํ”„๋กœ๋ฐ”์ด๋”์™€ ์ปจํ…์ŠคํŠธ๋ฅผ ํฌํ•จํ•ด ๋ชจํ‚นํ•ด์•ผ ํ•œ๋‹ค.

//Payment.spec.jsx
const TestPayment = (props = {}) => {
  const methods = useForm({
    defaultValues: {
      name: 'leejaesung',
      address: '',
      phone: '',
      requests: '',
      coupon: NO_COUPON_ID,
      ...props,
    },
  });

  return (
    <FormProvider {...methods}>
      <Payment />
    </FormProvider>
  );
};

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ ํ•œ๊ณ„

์œ„์˜ ํ†ตํ•ฉํ…Œ์ŠคํŠธ๋ฅผ ๋ณด๋ฉด ๊ตฌ๋งค ํŽ˜์ด์ง€์— ์žˆ๋Š” ๋„๋ฉ”์ธ๋ณ„๋กœ ์„ธ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์ž ํ…Œ์ŠคํŠธ ํ•˜๊ณ  ์žˆ๋‹ค. ๊ฐ ํ•ญ๋ชฉ์˜ ์ž…๋ ฅ๊ฐ’ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์ด ์ž˜ ์ด๋ฃจ์–ด์ง€๋Š”์ง€, ์ฟ ํฐ ๋ชฉ๋ก์ด ์ œ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋Š”์ง€, ์žฅ๋ฐ”๊ตฌ๋‹ˆ์˜ ๋ฌผํ’ˆ๊ณผ ์ด์•ก์ด ๋งž๊ฒŒ ๋‚˜์˜ค๋Š”์ง€ ๋“ฑ. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ชจ๋“  ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•œ๋‹ค๋Š”๊ฒƒ๊ณผ ์ƒํ’ˆ ๊ตฌ๋งค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋Š”๊ฒƒ์€ ๋‹ค๋ฅธ ๋ฌธ์ œ๋‹ค.

์ƒํ’ˆ ๊ตฌ๋งค ํ”„๋กœ์„ธ์Šค์—์„œ ๊ฒฐ๊ตญ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ ๋ฐฐ์†ก ์ •๋ณด ์ž…๋ ฅ ํ•„๋“œ์™€ ๊ฒฐ์ œ ๊ธˆ์•ก ์ •๋ณด, ๊ฒฐ์ œ ์ˆ˜๋‹จ ๋“ฑ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ API์— ์ „๋‹ฌํ•˜์—ฌ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ์ฃผ๋ฌธ์„œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งŒ๋“ค์–ด์ง€๊ณ  ์ดํ›„์— ๊ฒฐ์ œ ์„ฑ๊ณต๊ณผ ์‹คํŒจ์— ๋”ฐ๋ฅธ ํ๋ฆ„์ด ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ตฌ๋งค ํŽ˜์ด์ง€ ์ „์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด?

๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” cart ์Šคํ† ์–ด, user ์Šคํ† ์–ด์— ๋Œ€ํ•œ ๋ชจํ‚น๊ณผ ์ฟ ํฐ ๋ฆฌ์ŠคํŠธ api์™€ ๊ตฌ๋งคํ•˜๊ธฐ api ๋ชจ๋‘์— ๋Œ€ํ•œ ๋ชจํ‚น์ด ํ•„์š”ํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ตฌ๋งค ์„ฑ๊ณต, ์‹คํŒจ ์—ฌ๋ถ€๋„ ์–ด์ฐจํ”ผ ๋ชจํ‚น์— ์˜์กดํ•ด์•ผ ํ•œ๋‹ค.

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ์ด๋ ‡๊ฒŒ ํฐ ๊ทœ๋ชจ์˜, ์ „์ฒด ํ”„๋กœ์„ธ์Šค(์›Œํฌํ”Œ๋กœ์šฐ)๋ฅผ ๊ฒ€์ฆํ•˜๋Š”๋ฐ ์œ ํšจํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ๋„๋ฉ”์ธ ๋‹จ์œ„์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ์ปดํฌ๋„ŒํŠธ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ฒ€์ฆํ•˜๋Š”๋ฐ ๋งค์šฐ ํšจ์œจ์ ์ด๋‹ค.