Make jest + nock + axios + typescript work after upgrading axios from 0.28 to 1.5

195 Views Asked by At

I've been working with Axios to get content from Dynamic Yield. We were working with axios 0.28. Everything was working in frontend. We also had tests in typescript (jest + nock) that worked. But we've upgraded axios to latest (1.5) version. And now tests don't work any more.

I think that the problem is with the OPTIONS preflight request.

I've tried to cope with that, by intercepting OPTIONS request (before real POST request). But it doesn't work, whatever I try.

The tests look like this:

import { describe, expect, it } from '@jest/globals';
import nock from 'nock';
import type { Config } from './dependency-injection/config';
import type { ChooseApiRequest } from './api/contract/choose/ChooseApiRequest';
import type { Choice, ChooseApiResponse } from './api/contract/choose/ChooseApiResponse';
import { dy } from './services';

const API_KEY = '6394b44ef96243bf8e6e2aad7f59d389';
const CHOOSE_API_URL = 'https://direct.dy-api.eu/v2/serve/user/choose';

window.dynamicYieldConfig = {
    apiKey: API_KEY,
    chooseEndpointUrl: CHOOSE_API_URL,
} satisfies Config;

describe('Dynamic Yield: services.dy - the DynamicYield facade', () => {
    const CURRENT_URL = 'https://shop.de/';

    const server = nock('https://direct.dy-api.eu:443/')
        .matchHeader('Content-Type', 'application/json')
        .matchHeader('DY-API-KEY', API_KEY);

    it('should provide an abstraction over the `choose` endpoint (independent from cookies)', async () => {
        // nock.disableNetConnect();

        const CAMPAIGN_NAME = 'campaign';

        // given
        window.pageType = 'Home';
        window.location.assign(CURRENT_URL);

        const expectedRequest: ChooseApiRequest = {
            context: {
                page: {
                    type: 'HOMEPAGE',
                    data: [],
                    location: CURRENT_URL,
                },
            },
            selector: { names: [CAMPAIGN_NAME] },
            options: { isImplicitImpressionMode: true },
        };

        const choiceReturnedByServer: Choice = {
            id: 9999,
            name: CAMPAIGN_NAME,
            type: 'DECISION',
            decisionId: 'decision-id',
            variations: [
                {
                    id: 8888,
                    payload: {
                        type: 'CUSTOM_JSON',
                        data: { 'custom-key': 'custom-value' },
                    },
                },
            ],
        };

        server
            .persist()
            .intercept('/v2/serve/user/choose', 'OPTIONS').reply(204, '', {
            "Access-Control-Allow-Origin": "*",
            "Content-Type": "application:json"
        })
            // @ts-ignore
            .post('/v2/serve/user/choose', expectedRequest)
            .reply(200, {
                choices: [choiceReturnedByServer],
                cookies: [
                    {
                        name: '_dyjsession',
                        value: 'new-session-id-from-server',
                        maxAge: '3600',
                    },
                ],
                warnings: [],
            } satisfies ChooseApiResponse);

        await expect(
            (async () => {
                // when
                const result = await dy().choose({
                    selector: { names: [CAMPAIGN_NAME] },
                    options: { isImplicitImpressionMode: true },
                });

                // then
                expect(result.get('DECISION', CAMPAIGN_NAME)).toEqual(choiceReturnedByServer);
            })(),
        ).resolves.not.toThrowError();

        // without consent, DY shall not have session persistence with cookies
        expect(document.cookie).not.toContain('_dyjsession');
    });

   
});

Of course the expected result is for nock to mock the response and return the values defined in test.

When I'm using nock.recorder.rec() I'm getting following logs:

  console.log
    
    <<<<<<-- cut here -->>>>>>
    {
      "scope": "https://direct.dy-api.eu:443",
      "method": "OPTIONS",
      "path": "/v2/serve/user/choose",
      "body": "",
      "status": 204,
      "response": "",
      "rawHeaders": [
        "Server",
        "DynamicYieldAPI/2.0",
        "Date",
        "Tue, 05 Sep 2023 10:17:36 GMT",
        "Content-Length",
        "0",
        "Connection",
        "keep-alive",
        "Expires",
        "Tue, 05 Sep 2023 11:17:36 GMT",
        "Cache-Control",
        "max-age=3600",
        "Access-Control-Allow-Origin",
        "http://localhost",
        "Access-Control-Allow-Credentials",
        "true",
        "Access-Control-Allow-Methods",
        "GET, POST, PUT, PATCH, DELETE",
        "Access-Control-Allow-Headers",
        "DY-API-Key, Content-Type, Cache-Control, Authorization, Postman-Token, DY-Explain",
        "Access-Control-Max-Age",
        "1728000",
        "Allow",
        "POST,OPTIONS",
        "Vary",
        "Origin",
        "DY-Trace-ID",
        "25a4ebc36407952cdce0b83ad0e8d910",
        "P3P",
        "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CUR ADM DEV OUR BUS\"",
        "Content-Type",
        "application/json; charset=utf-8"
      ],
      "reqheaders": {
        "referer": "http://localhost/",
        "origin": "http://localhost",
        "access-control-request-method": "POST",
        "access-control-request-headers": "DY-API-KEY",
        "host": "direct.dy-api.eu"
      },
      "responseIsBinary": false
    }
    <<<<<<-- cut here -->>>>>>

      at IncomingMessage.<anonymous> (node_modules/nock/lib/recorder.js:280:13)

  console.log
    
    <<<<<<-- cut here -->>>>>>
    {
      "scope": "https://direct.dy-api.eu:443",
      "method": "POST",
      "path": "/v2/serve/user/choose",
      "body": {
        "context": {
          "page": {
            "type": "HOMEPAGE",
            "data": [],
            "location": "https://shop.de/"
          }
        },
        "selector": {
          "names": [
            "campaign"
          ]
        },
        "options": {
          "isImplicitImpressionMode": true
        }
      },
      "status": 401,
      "response": {
        "error": 401
      },
      "rawHeaders": [
        "Server",
        "DynamicYieldAPI/2.0",
        "Date",
        "Tue, 05 Sep 2023 10:17:36 GMT",
        "Transfer-Encoding",
        "chunked",
        "Connection",
        "keep-alive",
        "Access-Control-Allow-Origin",
        "http://localhost",
        "Access-Control-Allow-Credentials",
        "true",
        "Access-Control-Allow-Methods",
        "GET, POST, PUT, PATCH, DELETE",
        "Access-Control-Allow-Headers",
        "DY-API-Key, Content-Type, Cache-Control, Authorization, Postman-Token, DY-Explain",
        "Access-Control-Max-Age",
        "1728000",
        "Allow",
        "POST,OPTIONS",
        "DY-Trace-ID",
        "2e6eea7fe13ace0dd81abeaa565b4bd5",
        "P3P",
        "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CUR ADM DEV OUR BUS\"",
        "Content-Type",
        "application/json; charset=utf-8"
      ],
      "reqheaders": {
        "accept": "application/json, text/plain, */*",
        "content-type": "application/json",
        "dy-api-key": "6394b44ef96243bf8e6e2aad7f59d389",
        "referer": "http://localhost/",
        "accept-language": "en",
        "origin": "http://localhost",
        "content-length": 158,
        "accept-encoding": "gzip, deflate",
        "host": "direct.dy-api.eu"
      },
      "responseIsBinary": false
    }
    <<<<<<-- cut here -->>>>>>

      at IncomingMessage.<anonymous> (node_modules/nock/lib/recorder.js:280:13)


Error: expect(received).resolves.not.toThrowError()

Received promise rejected instead of resolved
Rejected to value: [AxiosError: Request failed with status code 401]

I'd say that the OPTIONS preflight request isn't intercepted ... but if I knew what's the problem I wouldn't be here right? :p

0

There are 0 best solutions below