'use strict';

const crypto = require('crypto');
const apiTokenService = require('../api-token');

describe('API Token', () => {
  afterAll(() => {
    jest.clearAllMocks();
  });

  describe('create', () => {
    test('Creates a new token', async () => {
      const create = jest.fn(({ data }) => Promise.resolve(data));

      const mockedApiToken = {
        randomBytes: 'api-token_test-random-bytes',
        hexedString: '6170692d746f6b656e5f746573742d72616e646f6d2d6279746573',
      };

      crypto.randomBytes = jest.fn(() => Buffer.from(mockedApiToken.randomBytes));

      global.strapi = {
        query() {
          return { create };
        },
        config: {
          get: jest.fn(() => ''),
        },
      };

      const attributes = {
        name: 'api-token_tests-name',
        description: 'api-token_tests-description',
        type: 'read-only',
      };

      const res = await apiTokenService.create(attributes);

      expect(create).toHaveBeenCalledWith({
        select: ['id', 'name', 'description', 'type'],
        data: {
          ...attributes,
          accessKey: apiTokenService.hash(mockedApiToken.hexedString),
        },
      });
      expect(res).toEqual({
        ...attributes,
        accessKey: mockedApiToken.hexedString,
      });
    });
  });

  describe('createSaltIfNotDefined', () => {
    test('It does nothing if the salt is alread defined', () => {
      const mockedAppendFile = jest.fn();
      const mockedConfigSet = jest.fn();

      global.strapi = {
        config: {
          get: jest.fn(() => ({
            server: {
              admin: { 'api-token': { salt: 'api-token_tests-salt' } },
            },
          })),
          set: mockedConfigSet,
        },
        fs: { appendFile: mockedAppendFile },
      };

      apiTokenService.createSaltIfNotDefined();

      expect(mockedAppendFile).not.toHaveBeenCalled();
      expect(mockedConfigSet).not.toHaveBeenCalled();
    });

    test('It creates a new salt, appends it to the .env file and sets it in the configuration', () => {
      const mockedApiToken = {
        randomBytes: 'api-token_test-random-bytes',
        hexedString: '6170692d746f6b656e5f746573742d72616e646f6d2d6279746573',
      };

      crypto.randomBytes = jest.fn(() => Buffer.from(mockedApiToken.randomBytes));

      const mockedAppendFile = jest.fn();
      const mockedConfigSet = jest.fn();

      global.strapi = {
        config: {
          get: jest.fn(() => null),
          set: mockedConfigSet,
        },
        fs: { appendFile: mockedAppendFile },
      };

      apiTokenService.createSaltIfNotDefined();

      expect(mockedAppendFile).toHaveBeenCalledWith(
        '.env',
        `API_TOKEN_SALT=${mockedApiToken.hexedString}\n`
      );
      expect(mockedConfigSet).toHaveBeenCalledWith(
        'server.admin.api-token.salt',
        mockedApiToken.hexedString
      );
    });

    test('It throws an error if the env variable used in the config file has been changed and is empty', () => {
      expect.assertions(1);
      process.env.API_TOKEN_SALT = 'api-token_tests-salt';

      global.strapi = {
        config: {
          get: jest.fn(() => null),
        },
      };

      try {
        apiTokenService.createSaltIfNotDefined();
      } catch (err) {
        expect(err).toBeInstanceOf(Error);
      }
    });
  });
});

@@ -126,207 +126,8 @@
 %3E %7B%0A
-  afterAll(() =%3E %7B%0A    jest.clearAllMocks();%0A  %7D);%0A%0A  describe('create', () =%3E %7B%0A    test('Creates a new token', async () =%3E %7B%0A      const create = jest.fn((%7B data %7D) =%3E Promise.resolve(data));%0A%0A    
   co
@@ -141,36 +141,32 @@
 kedApiToken = %7B%0A
-    
     randomBytes:
@@ -189,36 +189,32 @@
 -random-bytes',%0A
-    
     hexedString:
@@ -274,37 +274,71 @@
 573',%0A  
-    %7D;%0A%0A      
+%7D;%0A%0A  beforeAll(() =%3E %7B%0A    jest%0A      .spyOn(
 crypto
-.
+, '
 randomBy
@@ -336,33 +336,51 @@
 'randomBytes
- = jest.f
+')%0A      .mockImplementatio
 n(() =%3E Buff
@@ -408,32 +408,233 @@
 n.randomBytes));
+%0A  %7D);%0A%0A  afterAll(() =%3E %7B%0A    jest.clearAllMocks();%0A  %7D);%0A%0A  describe('create', () =%3E %7B%0A    test('Creates a new token', async () =%3E %7B%0A      const create = jest.fn((%7B data %7D) =%3E Promise.resolve(data));
 %0A%0A      global.s
@@ -2111,264 +2111,8 @@
 %3E %7B%0A
-      const mockedApiToken = %7B%0A        randomBytes: 'api-token_test-random-bytes',%0A        hexedString: '6170692d746f6b656e5f746573742d72616e646f6d2d6279746573',%0A      %7D;%0A%0A      crypto.randomBytes = jest.fn(() =%3E Buffer.from(mockedApiToken.randomBytes));%0A%0A
     

use spyOn to mock crypto