Документация по началу работы с Jest

внешний интерфейс JavaScript Promise Jest

Front-end тестирование Jest (продолжение следует)

1 Настройте среду

  1. node npm install --save-dev jest необходимо настроить в переменных среды
  2. yarn yarn add --dev jest yarn global add jest

2 demo

Все суффиксы файла проекта jest — xx.test.js.Когда мы запускаем проект jest, jest автоматически находит сценарии с суффиксом *.test.js для модульного тестирования.

machers Многочисленные факторы, определяющие матч

  1. toBe() используется для проверки равенства значений примитивных типов данных
  2. toEqual() используется для проверки значения эталонного типа данных.Из-за присущих объектному типу данных самого js сравнения эталонных типов данных — это только сравнение указателей, но каждое значение объекта необходимо следует сравнивать, поэтому в настоящее время используется toEqual().
  3. Сопоставитель для правдоподобных логических суждений
  • toBeNull соответствует только null
  • toBeUndefined соответствует только undefined
  • toBeDefined является противоположностью toBeUndefined
  • toBeTruthy соответствует любому истинному оператору if
  • toBeFalsy соответствует любому оператору if, который является ложным
  1. Сопоставитель чисел используется для определения сравнения между цифровыми значениями.
  • Тобегрегреэтфстан больше, чем соответствующий
  • toBeGreaterThanOrEqual больше или равно сопоставителю
  • toBeLessThan меньше, чем matcher
  • toBeLessThanOrEqual меньше или равно сопоставителю
  • tobe и toequal функционально эквивалентны для чисел
  1. Сопоставитель строк toMatch аналогичен сопоставлению строк
  2. Сопоставитель массива toContain используется для определения того, содержит ли массив определенные значения.
  3. Сопоставитель ошибок toThrow используется для проверки конкретной выброшенной ошибки, может оценивать текст оператора ошибки (поддерживается обычное сопоставление), а также может определять тип ошибки.

Оценка асинхронного кода

js основан на однопоточной асинхронной функции, а код полон асинхронных программ и различных обратных вызовов, поэтому при тестировании асинхронного кода следует уделять особое внимание. Вот различные асинхронные случаи

  1. обратный вызов
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});
 // 这种情况有问题,大家都知道一个ajax请求是一个事件(由两个事务发送和返回组成),当发送成功和返回成功这个事件就是完成的,就是成功的,这个时候jest就认为ajax事件完成了,所以检验会在回调判断执行前结束,没有验证data数据,所以这是有问题的。

Jest предоставляет соответствующий метод для решения такой проблемы, гарантируя, что обратный вызов будет выполнен для завершения всей проверки теста. Вызов выполняется с одним аргументом вместо того, чтобы помещать тест в функцию с пустым аргументом. Jest будет ждать завершения выполнения функции обратного вызова done, прежде чем завершить тест. давайте покажем код

test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});
  如果 done()永远不会调用,这个测试将失败,这也是你所希望发生的。
  1. Обещания Если код использует промисы для обработки асинхронных программ, у нас есть более простой способ асинхронного тестирования. Тест автоматически завершается неудачно, если состояние, возвращаемое промисом, равно отклонению.
    test('Promise test', ()=>{
        // 断言测试
        expect.assertions(1);
        // 一定记得return,否则测试拿不到promise的状态,测试会在fetchData()完成前完成。
        return fetchData().then(data=>{
            expect(data).tobe('promise')
        })
    })

Если ожидаемое обещание отклонено, мы можем поймать нашу ошибку с помощью catch. Не забудьте добавить expect.assertions, чтобы убедиться, что вызывается определенное количество утверждений. В противном случае выполненное Обещание не провалит проверку.

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});
  1. Сопоставители .resolves/.rejects В Jest есть специальные сопоставители для обработки обещаний, разрешений и отклонений. Используйте средство сопоставления разрешений для обработки промисов, и тест автоматически завершится неудачей, если возвращенный статус будет отклонен. Помните, чтобы не потерять возврат. Точно так же вы используете средство сопоставления отклонений для обработки, если вы хотите получить обещание, которое возвращает отклонение, но обещание выполняется успешно и возвращает успешное разрешение состояния (выполнено), результатом теста является отказ.
 // let's show code~
 // resolves
    test('the data is peanut butter', () => {
      expect.assertions(1);
      return expect(fetchData()).resolves.toBe('peanut butter');
    });
 // rejects
    test('the fetch fails with an error', () => {
      expect.assertions(1);
      return expect(fetchData()).rejects.toMatch('error');
    });
  1. Async/Await Вы также можете использовать async/await для обработки асинхронных тестов. Просто добавьте ключевое слово async перед тестовой функцией обратного вызова.
// 提前了解async和await的使用方法和场景

test('the data is peanut butter', async () => {
  // 切记添加断言测试
  expect.assertions(1);
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  // 切记添加断言测试
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});

Также можно смешивать .resolves/.rejects и Async/Await.

// 因为await本身返回的就是一个promise。所以我们可以在返回的promise的基础之上继续测试我们的代码。
test('the data is peanut butter', async () => {
  expect.assertions(1);
  await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  await expect(fetchData()).rejects.toMatch('error');
});

#Jest's Traversal, установка и разборка При выполнении некоторых повторяющихся тестовых настроек мы можем использовать beforeEach и afterEach. Предположим, нам нужно повторить некоторые тестовые настройки для данных взаимодействия. Предположим, что initializeCityDatabase() вызывается перед тестом, а clearCityDatabase() вызывается после теста. Затем мы можем использовать beforeEach и afterEach. давайте покажем код~

beforeEach and afterEach

    beforeEach(() => {
      initializeCityDatabase();
    });
    
    afterEach(() => {
      clearCityDatabase();
    });
    
    test('city database has Vienna', () => {
      expect(isCity('Vienna')).toBeTruthy();
    });
    
    test('city database has San Juan', () => {
      expect(isCity('San Juan')).toBeTruthy();
    });

BeforeEach и afterEach обрабатывают асинхронный код, вы также можете использовать done и promise.Если initializeCityDatabase() возвращает обещание, мы можем обработать его следующим образом. давайте покажем код

    beforeEach(()=>{
        return initializeCityDatabase(); // return一个promise
    })

beforeAll and afterAll

Scoping

Мы можем использовать функцию Jest описать для создания области действия с помощью идеи функционального программирования js для модульности наших тестов. Конкретный сценарий заключается в использовании описания для модуля области действия нашего foreach. давайте покажем код

// 这里的beforeEach适用于所有的test
beforeEach(() => {
  return initializeCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

describe('matching cities to foods', () => {
  // 这里beforeEach仅仅适用于describe中的测试
  beforeEach(() => {
    return initializeFoodDatabase();
  });

  test('Vienna <3 sausage', () => {
    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  });

  test('San Juan <3 plantains', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});

Так как существует так много beforeEach/afterEach и beforeAll/afterAll, давайте взглянем на наш порядок выполнения с описанием. Я верю, что после прочтения вы подумаете о js (очередь задач и область действия).

    beforeAll(() => console.log('1 - beforeAll'));
    afterAll(() => console.log('1 - afterAll'));
    beforeEach(() => console.log('1 - beforeEach'));
    afterEach(() => console.log('1 - afterEach'));
    test('', () => console.log('1 - test'));
    describe('Scoped / Nested block', () => {
      beforeAll(() => console.log('2 - beforeAll'));
      afterAll(() => console.log('2 - afterAll'));
      beforeEach(() => console.log('2 - beforeEach'));
      afterEach(() => console.log('2 - afterEach'));
      test('', () => console.log('2 - test'));
    });
    
    // 1 - beforeAll
    // 1 - beforeEach
    // 1 - test
    // 1 - afterEach
    // 2 - beforeAll
    // 1 - beforeEach
    // 2 - beforeEach
    // 2 - test
    // 2 - afterEach
    // 1 - afterEach
    // 2 - afterAll
    // 1 - afterAll
    
正如结果查看顺序,全局的会作用到describe内部。 注意执行顺序,beforeALL和afterAll只会执行一次, 全局的beforeEach作用到了describe中的test,还要注意的是after作用域中的after比全局的after先执行。
beforeAll 在beforeEach前先执行,而afterAll在afterEach后执行。

Если вы хотите выполнить только один тест среди множества тестов, это очень просто, вам нужно всего лишь добавить флаг .only в его оператор теста, а другие тесты будут пропускать .let's show code

// 只有这个test会跑
test.only('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

// 这个test则会跳过
test('this test will not run', () => {
  expect('A').toBe('A');
});