// test.func.js
const func = require("./func"); // func.js 요청

let num = 0;

test("0 더하기 1은 1이야", () => {
  num = func.add(num, 1);
  expect(num).toBe(1);
});

test("0 더하기 2은 2이야", () => {
  num = func.add(num, 2);
  expect(num).toBe(2);
});

test("0 더하기 3은 3이야", () => {
  num = func.add(num, 3);
  expect(num).toBe(3);
});

test("0 더하기 4은 4이야", () => {
  num = func.add(num, 4);
  expect(num).toBe(4);
});

// 결과는?
// Tests:       3 failed, 1 passed, 4 total
// 처음 0 더하기 1 만 통과 되었다.

// 0 더하기 2
// Expected: 2
// Received: 3

// 0 더하기 3
// Expected: 3
// Received: 6

// 0 더하기 4
// Expected: 4
// Received: 10

// 오.. num 이 누적되고 있는거 같지 않은가? 매 테스트 num을 새로 초기화 해 주자.
const func = require("./func"); // func.js 요청

let num = 0;

// 테스트 해 주기전에 실행하라
beforeEach(() => {
  num = 0;
})

// 테스트 이후에 실행하라
afterEach(() => {
  num = 10;
})
// func.js
// 테스트 실행전에 DB 에 연결해서 USER 객체를 받아오고
const fn = {
  add: (num1, num2) => num1 + num2,
  connectUserDB: () => {
    return new Promise((res, rej) => {
      setTimeout(() => {
        res({
          name: "Malza",
          age: 29,
          gender: "male",
        });
      }, 500);
    });
  },
// 테스트 이후에 DB 연결을 끊는다.
  disconnectDB: () => {
    return new Promise((res, rej) => {
      setTimeout(() => {
        res(console.log("disconnect DB"));
      }, 500);
    });
  },
};

module.exports = fn;

====================================================================================
// func.test.js
const func = require("./func"); // func.js 요청

let user;

// 테스트 전, 후로 0.5초씩 소요된다.
beforeEach(async () => {
  user = await func.connectUserDB(); // 0.5초
});
afterEach(() => {
  return func.disconnectDB(); // 0.5초
});

test("user 의 이름은 Malza 입니다.", () => {
  expect(user.name).toBe("Malza");
});

//Time:        3.013 s

// 그렇지만 이러한 테스트가 여러개라고 해 보자.
// 매번 DB를 끊어주고 연결하는 방식은 매우 비효율적이다. 최초에 한번, 끝날 때 한번 해주면 된다.
const func = require("./func"); // func.js 요청

let user;

// 테스트 실행전 한번, 모든 테스트 후 한번
beforeAll(async () => {
  user = await func.connectUserDB();
});
afterAll(() => {
  return func.disconnectDB();
});

test("user 의 이름은 Malza 입니다.", () => {
  expect(user.name).toBe("Malza");
});

test("user 의 나이는 29살 입니다.", () => {
  expect(user.age).toBe(29);
});

test("user 의 성별은 male 입니다.", () => {
  expect(user.gender).toBe("male");
});

// Time:        3.034 s
// 유저의 db 뿐 아니라 car 의 db 도 같이 받아오자.
// func.js
const fn = {
  add: (num1, num2) => num1 + num2,
  connectUserDB: () => {
    return new Promise((res, rej) => {
      setTimeout(() => {
        res({
          name: "Malza",
          age: 29,
          gender: "male",
        });
      }, 500);
    });
  },
  disconnectDB: () => {
    return new Promise((res, rej) => {
      setTimeout(() => {
        res(console.log("disconnect DB"));
      }, 500);
    });
  },
  connectCarDB: () => {
    return new Promise((res, rej) => {
      setTimeout(() => {
        res({
          brand: "bmw",
          name: "z4",
          color: "black",
        });
      }, 500);
    });
  },
  disconnectCarDB: () => {
    return new Promise((res, rej) => {
      setTimeout(() => {
        res(console.log("disconnect Car DB"));
      }, 500);
    });
  },
};

module.exports = fn;

====================================================================================

// func.test.js
const func = require("./func"); // func.js 요청

let user;

beforeAll(async () => {
  user = await func.connectUserDB();
});
afterAll(() => {
  return func.disconnectDB();
});

test("user 의 이름은 Malza 입니다.", () => {
  expect(user.name).toBe("Malza");
});

test("user 의 나이는 29살 입니다.", () => {
  expect(user.age).toBe(29);
});

test("user 의 성별은 male 입니다.", () => {
  expect(user.gender).toBe("male");
});

// describe 로 Car 관련은 묶어준다.
describe("Car 관련 작업", () => {
  let car;

  beforeAll(async () => {
    car = await func.connectCarDB();
  });
  afterAll(() => {
    return func.disconnectCarDB();
  });

  test("car 의 brand는 bmw 입니다.", () => {
    expect(car.brand).toBe("bmw");
  });

  test("car 의 name은 z4 입니다.", () => {
    expect(car.name).toBe("z4");
  });

  test("car 의 color는 black 입니다.", () => {
    expect(car.color).toBe("black");
  });
});

// PASS  ./func.test.js
//   √ user 의 이름은 Malza 입니다. (2 ms)
//   √ user 의 나이는 29살 입니다. (1 ms)
//     √ user 의 성별은 male 입니다. (1 ms)
//     Car 관련 작업
//       √ car 의 brand는 bmw 입니다. (1 ms)
//       √ car 의 name은 z4 입니다.
//       √ car 의 color는 black 입니다. (1 ms)
// 그렇다면 describe 로 감싸서 다른 test 를 추가적으로 할 때
// before, after 함수의 순서는 어떻게 작동될까?

const func = require("./func"); // func.js 요청

beforeAll(() => console.log("밖의 beforeAll")); // 1
beforeEach(() => console.log("밖의 beforeEach")); // 2, 6
afterEach(() => console.log("밖의 afterEach"));  // 4, 10
afterAll(() => console.log("밖의 afterAll"));  // 12

test("밖의 더하기 함수 0 + 1 = 1", () => {
  expect(func.add(0, 1)).toBe(1); // 3
});

describe("describe", () => {
  beforeAll(() => console.log("안의 beforeAll")); // 5
  beforeEach(() => console.log("안의 beforeEach")); // 7
  afterEach(() => console.log("안의 afterEach"));  // 9
  afterAll(() => console.log("안의 afterAll"));  // 11

  test("안의 더하기 함수 0 + 1 = 1", () => {
    expect(func.add(0, 1)).toBe(1);  // 8
  });
});

// 외부의 beforeEach 는 describe 내부보다 항상 먼저 실행된다.
// afterEach 는 describe 내부가 먼저 실행된다.
test.only() // 이 테스트만 진행하라
test.skip() // 해당 테스트는 스킵하라