RxJS:如何用诺克测试 Observable.ajax() ?

RxJS: How to test Observable.ajax() with nock?

我目前正在学习 RxJS,我正在尝试弄清楚如何使用 nock 来测试 Observable.ajax()

这是我的简化示例,没有任何断言...我只是想看看 nock 是否可以拦截 API 调用。

import { afterEach, describe, it } from 'mocha';
import nock from 'nock';
import { ajax } from 'rxjs/observable/dom/ajax';

// had to use `crossDomain: true` for it to work in production code
const api = ajax({
  url: 'https://server.com/abc',
  crossDomain: true,
});

describe('ajax', () => {
  afterEach(() => {
    nock.cleanAll();
  });

  it('given valid call, should return value', (done) => {
    nock('https://server.com', {
      // needed to prevent "cross origin null forbidden" error
      reqheaders: {
        'Access-Control-Allow-Origin': '*',
      },
    }).get('/abc').reply(200, 'YAY!');

    api
      .map(e => e.json())
      .subscribe(
        value => console.log('SUCCESS', value),
        error => console.log('ERROR', error),
        () => done(),
      );
  });
});

执行上述代码时,我无法获得预期值 ("YAY!")。

相反,我得到了这个错误:-

Error: Error: Nock: No match for request {
  "method": "GET",
  "url": "https://server.com/abc",
  "headers": {
    "referer": "about:blank",
    "user-agent": "Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/11.2.0",
    "accept-language": "en",
    "accept": "*/*",
    "origin": "null",
    "host": "server.com",
    "accept-encoding": "gzip, deflate"
  }
}

subscribe(..) 上的 console.log(..) 显示:-

ERROR { [Error: ajax error]
  message: 'ajax error',
  xhr: 
   XMLHttpRequest {
     upload: XMLHttpRequestUpload { _ownerDocument: [Object] },
     _eventHandlers: { readystatechange: [Object] },
     [Symbol(flag)]: 
      { synchronous: false,
        withCredentials: false,
        mimeType: null,
        auth: null,
        method: 'GET',
        responseType: 'json',
        requestHeaders: {},
        referrer: 'about:blank',
        uri: 'https://server.com/abc',
        timeout: 0,
        body: undefined,
        formData: false,
        preflight: false,
        requestManager: [Object],
        pool: undefined,
        agentOptions: undefined,
        strictSSL: undefined,
        proxy: undefined,
        cookieJar: [Object],
        encoding: 'UTF-8',
        origin: 'null',
        userAgent: 'Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/11.2.0' },
     [Symbol(properties)]: 
      { beforeSend: false,
        send: false,
        timeoutStart: 0,
        timeoutId: 0,
        timeoutFn: null,
        client: [Object],
        responseHeaders: {},
        filteredResponseHeaders: [],
        responseBuffer: null,
        responseCache: null,
        responseTextCache: null,
        responseXMLCache: null,
        responseURL: '',
        readyState: 4,
        status: 0,
        statusText: '',
        error: [Object],
        uploadComplete: true,
        uploadListener: false,
        abortError: false,
        cookieJar: [Object],
        bufferStepSize: 1048576,
        totalReceivedChunkSize: 0,
        requestBuffer: null,
        requestCache: null,
        origin: 'null' } },
  request: 
   { async: true,
     createXHR: [Function: createXHR],
     crossDomain: true,
     withCredentials: false,
     headers: {},
     method: 'GET',
     responseType: 'json',
     timeout: 0,
     url: 'https://server.com/abc',
     body: undefined },
  status: 0 }

我的问题是如何配置 nock 以正确拦截 API 调用?

有没有更好的方法可以在不使用 nock 的情况下测试 API 调用?

谢谢。

我明白了。关键是在初始化JSDOM.

时定义匹配被测API的url

这是带有断言的工作版本:-

import { afterEach, describe, it } from 'mocha';
import nock from 'nock';
import { expect } from 'chai';
import { ajax } from 'rxjs/observable/dom/ajax';
import { JSDOM } from 'jsdom';

// defining `url` is important!!
const { window } = new JSDOM('', { url: 'https://server.com' });

const apiUnderTest = ajax({
  url: 'https://server.com/abc',
  crossDomain: true,
  createXHR: () => new window.XMLHttpRequest(),
});

describe('ajax', () => {
  const expectedValue = 'YAY!';

  afterEach(() => {
    nock.cleanAll();
  });

  it('given successful call, should return value', (done) => {
    nock('https://server.com').get('/abc').reply(200, { value: expectedValue });

    apiUnderTest
      .map(e => e.response.value)
      .subscribe(
        (actualValue) => {
          expect(actualValue).to.deep.equal(expectedValue);
          done();
        },
        (error) => {
          expect(error).to.be.an('undefined');
          done();
        },
      );
  });

  it('given failed call, should not return value', (done) => {
    nock('https://server.com').get('/abc').reply(400, { value: expectedValue });

    apiUnderTest
      .map(e => e.response.value)
      .subscribe(
        (actualValue) => {
          expect.fail(actualValue, undefined, 'Should not have value');
          done();
        },
        (error) => {
          expect(error).to.not.be.an('undefined');
          done();
        },
      );
  });
});