Как использовать nock для перехвата запросов независимо от тела

Я пытаюсь использовать nock в своих тестах для перехвата вызовов запросов, которые я делаю из собственного модуля https в Node.js. I'm using Promise.all сделать два запроса на внешний сервер. Я хочу, чтобы мои тесты перехватывали вызовы и проверяли некоторые поля формы, чтобы убедиться, что они заполнены так, как я хочу.

У меня есть настройка моего класса ниже (сохранены наиболее важные части кода):

const archiver = require('archiver');
const { generateKeyPairSync } = require('crypto');
const FormData = require('form-data');
const fs = require('fs');
const https = require('https');

class Platform {
  constructor() {
    this.FILESTORE_USERNAME = process.env.FILESTORE_USERNAME;
    this.FILESTORE_PASSWORD = process.env.FILESTORE_PASSWORD;
  }

  store(serviceName) {
    const { publicKey, privateKey } = this._generateKeys();

    return Promise.all([this._postKey(publicKey), this._postKey(privateKey)])
      .then(() => {
        return this._zipKeys(publicKey, privateKey, serviceName);
      })
      .catch((err) => {
        throw err;
      });
  }

  _postKey(key) {
    const options = this._getOptions();
    const keyName = (key.search(/(PUBLIC)/) !== -1) ? 'publicKey' : 'privateKey';
    const form = new FormData();
    form.append('file', key);
    form.append('Name', keyName);
    form.append('MimeMajor', 'application');
    form.append('MimeMinor', 'x-pem-file');
    form.append('Extension', (keyName == 'publicKey') ? 'pub' : '');
    form.append('FileClass', 'MFS::File');
    options.headers = form.getHeaders();
    options.headers.Authorization = 'Basic ' + Buffer.from(this.FILESTORE_USERNAME + ':' + this.FILESTORE_PASSWORD).toString('base64');

    return new Promise((resolve, reject) => {
      let post = https.request(options, (res) => {
        let data = '';
        if (res.statusCode < 200 || res.statusCode > 299) {
          reject(new Error('File Storage API returned a status code outside of acceptable range: ' + res.statusCode));
        } else {
          res.setEncoding('utf8');
          res.on('data', (chunk) => {
            data += chunk;
          });

          res.on('error', (err) => {
            reject(err);
          });

          res.on('end', () => {
            if (data) {
              resolve(JSON.parse(data));
            } else {
              resolve();
            }
          });
        }
      });
      post.on('error', (err) => {
        reject(err);
      });
      form.pipe(post);
      post.end();

    });
  }

  _getOptions() {
    return {
      hostname: 'api.example.com',
      path: '/media/files/',
      method: 'POST',
    };
  }
}

module.exports = Platform;

И тогда мой тестовый код выглядит так, как показано ниже. Я использую мокко, синон, чай, синон-чай и нок.

const Platform = require('/usr/src/app/api/Services/Platform');
const crypto = require('crypto');
const fs = require('fs');
const nock = require('nock');
const yauzl = require('yauzl');

describe('Platform', function() {
  let platform;
  beforeEach(() => {
    platform = new Platform();
  });
  afterEach(() => {
    const list = fs.readdirSync('/usr/src/app/api/Services/data/');
    list.forEach((file) => {
      fs.unlink('/usr/src/app/api/Services/data/' + file, (err) => {
        if (err) throw err;
      });
    });
    nock.cleanAll();
  });
  after(() => {
    nock.restore();
  });
  describe('store', function() {
    it('should post each generated key to an external storage place', async function() {
      this.timeout(5000);
      // const stub = sinon.stub(platform, '_postKey').resolves();
      const scope = nock('https://api.example.com')
        .persist()
        .post('/media/files/', (body) => {
          // console.log(body);
        })
        .reply(200);

      let serviceName = 'test';
      let actual = await platform.store(serviceName)
        .catch((err) => {
          (() => { throw err; }).should.not.throw();
        });

      console.log(scope);
      // expect(stub.callCount).to.equal(2);
      expect(actual).to.be.a('string');
      expect(actual).to.include(serviceName + '.zip');
      // stub.reset();

    });
  });
});

Проблема, с которой я сталкиваюсь, заключается в этой ошибке, которая возникает при запуске моих тестов:

AssertionError: ожидалось, что [Function] не выдаст ошибку, но «Ошибка: Nock: не соответствует запросу {\n «метод»: «POST»,\n «url»: «https://api.example.com/media/files/",\n "headers": {\n
"content -type": "multipart/form-data; border=----------------------------------------363749230271182821931703",\n
"авторизация" : "Basic abcdef1224u38454857483hfjdhjgtuyrwyt="\n },\n "тело":" ----------------------------363749230271182821931703\r\nСодержимое -Disposition: form-data; name=\"file\"\r\n\r\n-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq+QnVOYVjbrHIlAEsEoF\nZ4sTvqiB3sJGwecNhmgrUp9U8oqgoB50aW6VMsL71ATRyq9b3vMQKpjbU3R2RcOF\na6mlaBtBjxDGu2nEpGX++mtPCdD9HV7idvWgJ3XS0vGaCM//8ukY+ VLBc1IB8CHC\nVj+8YOD5Y9TbdpwXR+0zCaiHwwd8MHIo1kBmQulIL7Avtjh55OmQZZtjO525lbqa\nWUZ24quDp38he2GjLDeTzHm9z1RjYJG6hS+Ui0s2xRUs6VAr7KFtiJmmjxPS9/vZ\nwQyFcz/R7AJKoEH8p7NE7nn/onbybJy+SWRxjXVH8afHkVoC65BiNoMiEzk1rI sx\ns92woHnq227JzYwFYcLD0W+TYjtGCB8+ks+QRIiV0pFJ3ja5VFIxjn9MxLntWcf2\nhsiYrmfJlqmpW1DMfZrtt41cJUFQwt7CpN72aix7btmd/q0syh6VVlQEHq/0nDky\nItv7dqyqZc9NNOMqK9/kXWhbq5cwS21mm+kTGas5KSdeIR0LH7uVtivB+LKum14e\nRDGascZcXZIVTbOeCxA6BD7LyaJPzXmlMy4spXlhGoDYyVRhpvv2K03Mg7ybiB4X\nEL1oJtiCFkRX5LtRJv0PCRJjaa3UvfyIuz8bHK4ANxIZqcwZwER+g02gw8iqNfMa\nDWXpfMJUU8TQuLGWZQaGJc8CAwEAAQ==\n-----END PUBLIC KEY-----\n \r\n--------------363749230271182821931703\r\nContent-Disposition: form-data; name=\"Имя\"\r\n\r\npublicKey\r\n---------------363749230271182821931703\r \nContent-Disposition: данные формы; name=\"MimeMajor\"\r\n\r\napplication\r\n ---------------------------- 363749230271182821931703\r \nContent-Disposition: данные формы; name=\"MimeMinor\"\r\n\r\nx-pem-file\r\n------------- -363749230271182821931703\r\nContent-Disposition: form-data; name=\"Расширение\"\r\n\r\npub\r\n---------------363749230271182821931703\r \nContent-Disposition: данные формы; name=\"FileClass\"\r\n\r\nMFS::File\r\n--------------- 363749230271182821931703 --\r\n"\n}' было брошено

Я так понимаю, это потому, что nock ожидает, что я подделаю тело для запроса, чтобы получить правильное совпадение? Есть ли способ просто искать запросы, сделанные на этот адрес, независимо от тела, чтобы я мог проводить свои собственные тесты или что-то еще.


person Jarede    schedule 05.06.2019    source источник


Ответы (1)


Когда методу post Nock Scope передается второй аргумент, он используется для сопоставления с телом запроса.

Документы по указанию тела запроса

В вашем тесте вы передаете функцию в качестве второго аргумента, но не возвращаете true, поэтому Нок не считает это совпадением.

Из документов:

Функция: nock будет оценивать функцию, предоставляющую объект тела запроса в качестве первого аргумента. Вернуть true, если это следует считать совпадением

Поскольку ваша цель состоит в утверждении полей формы в запросе, лучшим подходом будет оставить функцию там, выполнять утверждения там, где находится строка // console.log(body);, но добавить return true; в конец функции.

Вы также можете вернуть true или false в зависимости от того, соответствуют ли ваши поля формы вашим утверждениям, но по моему опыту это делает вывод ошибки из теста запутанным. Я предпочитаю использовать стандартные вызовы chai expect() и позволять утверждениям всплывать ошибки, прежде чем Nock продолжит сопоставление запросов.

person Matt R. Wilson    schedule 05.06.2019