mirror of
https://github.com/duhanbalci/iyzico.git
synced 2026-03-03 20:29:18 +00:00
init
This commit is contained in:
62
tests/unit/auth.test.ts
Normal file
62
tests/unit/auth.test.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Authentication unit tests
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { generateAuthorization } from '../../src/auth';
|
||||
|
||||
describe('generateAuthorization', () => {
|
||||
const apiKey = 'sandbox-api-key';
|
||||
const secretKey = 'sandbox-secret-key';
|
||||
const uriPath = '/payment/bin/check';
|
||||
|
||||
it('should generate authorization header with request body', () => {
|
||||
const requestBody = { binNumber: '589004', locale: 'tr' };
|
||||
const result = generateAuthorization(apiKey, secretKey, uriPath, requestBody);
|
||||
|
||||
expect(result.authorization).toMatch(/^IYZWSv2 /);
|
||||
expect(result.randomKey).toBeTruthy();
|
||||
expect(result.randomKey.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should generate authorization header without request body', () => {
|
||||
const result = generateAuthorization(apiKey, secretKey, uriPath);
|
||||
|
||||
expect(result.authorization).toMatch(/^IYZWSv2 /);
|
||||
expect(result.randomKey).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should generate different random keys for each call', () => {
|
||||
const result1 = generateAuthorization(apiKey, secretKey, uriPath);
|
||||
const result2 = generateAuthorization(apiKey, secretKey, uriPath);
|
||||
|
||||
expect(result1.randomKey).not.toBe(result2.randomKey);
|
||||
});
|
||||
|
||||
it('should use provided random key when given', () => {
|
||||
const customRandomKey = '123456789';
|
||||
const result = generateAuthorization(apiKey, secretKey, uriPath, undefined, customRandomKey);
|
||||
|
||||
expect(result.randomKey).toBe(customRandomKey);
|
||||
});
|
||||
|
||||
it('should generate valid base64 encoded authorization', () => {
|
||||
const result = generateAuthorization(apiKey, secretKey, uriPath);
|
||||
const base64Part = result.authorization.replace('IYZWSv2 ', '');
|
||||
|
||||
// Base64 should be valid (only contains A-Z, a-z, 0-9, +, /, =)
|
||||
expect(base64Part).toMatch(/^[A-Za-z0-9+/=]+$/);
|
||||
});
|
||||
|
||||
it('should include apiKey, randomKey, and signature in authorization string', () => {
|
||||
const customRandomKey = '123456789';
|
||||
const result = generateAuthorization(apiKey, secretKey, uriPath, undefined, customRandomKey);
|
||||
const base64Part = result.authorization.replace('IYZWSv2 ', '');
|
||||
const decoded = Buffer.from(base64Part, 'base64').toString('utf-8');
|
||||
|
||||
expect(decoded).toContain(`apiKey:${apiKey}`);
|
||||
expect(decoded).toContain(`randomKey:${customRandomKey}`);
|
||||
expect(decoded).toContain('signature:');
|
||||
});
|
||||
});
|
||||
|
||||
97
tests/unit/client.test.ts
Normal file
97
tests/unit/client.test.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Client unit tests
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { IyzicoClient } from '../../src/client';
|
||||
|
||||
describe('IyzicoClient', () => {
|
||||
const apiKey = 'test-api-key';
|
||||
const secretKey = 'test-secret-key';
|
||||
|
||||
it('should create a client with required config', () => {
|
||||
const client = new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey,
|
||||
});
|
||||
|
||||
expect(client.apiKey).toBe(apiKey);
|
||||
expect(client.secretKey).toBe(secretKey);
|
||||
expect(client.baseUrl).toBe('https://sandbox-api.iyzipay.com');
|
||||
expect(client.locale).toBe('tr');
|
||||
});
|
||||
|
||||
it('should throw error when apiKey is missing', () => {
|
||||
expect(() => {
|
||||
new IyzicoClient({
|
||||
apiKey: '',
|
||||
secretKey,
|
||||
} as any);
|
||||
}).toThrow('API key is required');
|
||||
});
|
||||
|
||||
it('should throw error when secretKey is missing', () => {
|
||||
expect(() => {
|
||||
new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey: '',
|
||||
} as any);
|
||||
}).toThrow('Secret key is required');
|
||||
});
|
||||
|
||||
it('should use custom baseUrl when provided', () => {
|
||||
const customUrl = 'https://api.custom.com';
|
||||
const client = new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl: customUrl,
|
||||
});
|
||||
|
||||
expect(client.baseUrl).toBe(customUrl);
|
||||
});
|
||||
|
||||
it('should use custom locale when provided', () => {
|
||||
const client = new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey,
|
||||
locale: 'en',
|
||||
});
|
||||
|
||||
expect(client.locale).toBe('en');
|
||||
});
|
||||
|
||||
it('should initialize all services', () => {
|
||||
const client = new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey,
|
||||
});
|
||||
|
||||
expect(client.payment).toBeDefined();
|
||||
expect(client.binCheck).toBeDefined();
|
||||
expect(client.cancelRefund).toBeDefined();
|
||||
expect(client.cardStorage).toBeDefined();
|
||||
expect(client.reporting).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return locale via getLocale()', () => {
|
||||
const client = new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey,
|
||||
locale: 'en',
|
||||
});
|
||||
|
||||
expect(client.getLocale()).toBe('en');
|
||||
});
|
||||
|
||||
it('should return baseUrl via getBaseUrl()', () => {
|
||||
const customUrl = 'https://api.custom.com';
|
||||
const client = new IyzicoClient({
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl: customUrl,
|
||||
});
|
||||
|
||||
expect(client.getBaseUrl()).toBe(customUrl);
|
||||
});
|
||||
});
|
||||
|
||||
76
tests/unit/errors.test.ts
Normal file
76
tests/unit/errors.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Error classes unit tests
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
IyzicoError,
|
||||
IyzicoRequestError,
|
||||
IyzicoResponseError,
|
||||
} from '../../src/errors';
|
||||
import type { ErrorResponse } from '../../src/types';
|
||||
|
||||
describe('IyzicoError', () => {
|
||||
it('should create error with message', () => {
|
||||
const error = new IyzicoError('Test error');
|
||||
expect(error.message).toBe('Test error');
|
||||
expect(error.name).toBe('IyzicoError');
|
||||
expect(error.code).toBeUndefined();
|
||||
expect(error.originalError).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should create error with code and originalError', () => {
|
||||
const originalError = new Error('Original error');
|
||||
const error = new IyzicoError('Test error', 'TEST_CODE', originalError);
|
||||
expect(error.message).toBe('Test error');
|
||||
expect(error.code).toBe('TEST_CODE');
|
||||
expect(error.originalError).toBe(originalError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('IyzicoRequestError', () => {
|
||||
it('should create request error', () => {
|
||||
const error = new IyzicoRequestError('Request failed');
|
||||
expect(error.message).toBe('Request failed');
|
||||
expect(error.name).toBe('IyzicoRequestError');
|
||||
expect(error.code).toBe('REQUEST_ERROR');
|
||||
});
|
||||
|
||||
it('should create request error with originalError', () => {
|
||||
const originalError = new Error('Validation error');
|
||||
const error = new IyzicoRequestError('Request failed', originalError);
|
||||
expect(error.message).toBe('Request failed');
|
||||
expect(error.code).toBe('REQUEST_ERROR');
|
||||
expect(error.originalError).toBe(originalError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('IyzicoResponseError', () => {
|
||||
it('should create response error', () => {
|
||||
const errorResponse: ErrorResponse = {
|
||||
status: 'failure',
|
||||
errorCode: 'PAYMENT_FAILED',
|
||||
errorMessage: 'Payment failed',
|
||||
};
|
||||
const error = new IyzicoResponseError('Payment failed', errorResponse);
|
||||
expect(error.message).toBe('Payment failed');
|
||||
expect(error.name).toBe('IyzicoResponseError');
|
||||
expect(error.code).toBe('PAYMENT_FAILED');
|
||||
expect(error.errorResponse).toEqual(errorResponse);
|
||||
});
|
||||
|
||||
it('should create response error with originalError', () => {
|
||||
const errorResponse: ErrorResponse = {
|
||||
status: 'failure',
|
||||
errorCode: 'PAYMENT_FAILED',
|
||||
errorMessage: 'Payment failed',
|
||||
};
|
||||
const originalError = new Error('Network error');
|
||||
const error = new IyzicoResponseError('Payment failed', errorResponse, originalError);
|
||||
expect(error.message).toBe('Payment failed');
|
||||
expect(error.code).toBe('PAYMENT_FAILED');
|
||||
expect(error.errorResponse).toEqual(errorResponse);
|
||||
expect(error.originalError).toBe(originalError);
|
||||
});
|
||||
});
|
||||
|
||||
310
tests/unit/http.test.ts
Normal file
310
tests/unit/http.test.ts
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* HTTP client unit tests
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { makeRequest } from '../../src/http';
|
||||
import {
|
||||
IyzicoResponseError,
|
||||
IyzicoRequestError,
|
||||
IyzicoError,
|
||||
} from '../../src/errors';
|
||||
|
||||
describe('makeRequest', () => {
|
||||
const apiKey = 'test-api-key';
|
||||
const secretKey = 'test-secret-key';
|
||||
const baseUrl = 'https://api.test.com';
|
||||
|
||||
// Store original fetch to restore it later
|
||||
const originalFetch = globalThis.fetch;
|
||||
const mockFetch = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock fetch before each test
|
||||
globalThis.fetch = mockFetch as any;
|
||||
mockFetch.mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Restore original fetch after each test
|
||||
globalThis.fetch = originalFetch;
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should make a successful POST request', async () => {
|
||||
const mockResponse = {
|
||||
status: 'success',
|
||||
data: 'test data',
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockResponse,
|
||||
});
|
||||
|
||||
const result = await makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockResponse);
|
||||
expect(mockFetch).toHaveBeenCalledTimes(1);
|
||||
const callArgs = mockFetch.mock.calls[0];
|
||||
expect(callArgs[0]).toBe('https://api.test.com/test');
|
||||
expect(callArgs[1].method).toBe('POST');
|
||||
expect(callArgs[1].headers).toHaveProperty('Authorization');
|
||||
expect(callArgs[1].headers).toHaveProperty('Content-Type', 'application/json');
|
||||
expect(callArgs[1].headers).toHaveProperty('x-iyzi-rnd');
|
||||
});
|
||||
|
||||
it('should make a successful GET request without body', async () => {
|
||||
const mockResponse = {
|
||||
status: 'success',
|
||||
data: 'test data',
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockResponse,
|
||||
});
|
||||
|
||||
const result = await makeRequest({
|
||||
method: 'GET',
|
||||
path: '/test',
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockResponse);
|
||||
expect(mockFetch).toHaveBeenCalledTimes(1);
|
||||
const callArgs = mockFetch.mock.calls[0];
|
||||
expect(callArgs[1].body).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should throw IyzicoResponseError for failure responses', async () => {
|
||||
const errorResponse = {
|
||||
status: 'failure',
|
||||
errorCode: 'TEST_ERROR',
|
||||
errorMessage: 'Test error message',
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: false,
|
||||
json: async () => errorResponse,
|
||||
});
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoResponseError);
|
||||
});
|
||||
|
||||
it('should throw IyzicoResponseError for failure status in response', async () => {
|
||||
const errorResponse = {
|
||||
status: 'failure',
|
||||
errorCode: 'TEST_ERROR',
|
||||
errorMessage: 'Test error message',
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => errorResponse,
|
||||
});
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoResponseError);
|
||||
});
|
||||
|
||||
it('should use fallback message when errorMessage is missing', async () => {
|
||||
const errorResponse = {
|
||||
status: 'failure',
|
||||
errorCode: 'TEST_ERROR',
|
||||
// errorMessage is missing
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => errorResponse,
|
||||
});
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoResponseError);
|
||||
});
|
||||
|
||||
it('should handle network errors with fetch in message', async () => {
|
||||
const networkError = new TypeError('Failed to fetch');
|
||||
mockFetch.mockRejectedValueOnce(networkError);
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoRequestError);
|
||||
});
|
||||
|
||||
it('should rethrow IyzicoResponseError', async () => {
|
||||
const errorResponse = {
|
||||
status: 'failure',
|
||||
errorCode: 'TEST_ERROR',
|
||||
errorMessage: 'Test error',
|
||||
} as const;
|
||||
const responseError = new IyzicoResponseError('Test error', errorResponse);
|
||||
mockFetch.mockRejectedValueOnce(responseError);
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoResponseError);
|
||||
});
|
||||
|
||||
it('should rethrow IyzicoRequestError', async () => {
|
||||
const requestError = new IyzicoRequestError('Request failed');
|
||||
mockFetch.mockRejectedValueOnce(requestError);
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoRequestError);
|
||||
});
|
||||
|
||||
it('should rethrow IyzicoError', async () => {
|
||||
const iyzicoError = new IyzicoError('Iyzico error');
|
||||
mockFetch.mockRejectedValueOnce(iyzicoError);
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoError);
|
||||
});
|
||||
|
||||
it('should wrap unknown errors in IyzicoError', async () => {
|
||||
const unknownError = new Error('Unknown error');
|
||||
mockFetch.mockRejectedValueOnce(unknownError);
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoError);
|
||||
});
|
||||
|
||||
it('should wrap non-Error objects in IyzicoError', async () => {
|
||||
mockFetch.mockRejectedValueOnce('String error');
|
||||
|
||||
await expect(
|
||||
makeRequest({
|
||||
method: 'POST',
|
||||
path: '/test',
|
||||
body: { test: 'value' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
}),
|
||||
).rejects.toThrow(IyzicoError);
|
||||
});
|
||||
|
||||
it('should handle DELETE request with body', async () => {
|
||||
const mockResponse = {
|
||||
status: 'success',
|
||||
data: 'deleted',
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockResponse,
|
||||
});
|
||||
|
||||
const result = await makeRequest({
|
||||
method: 'DELETE',
|
||||
path: '/test',
|
||||
body: { id: '123' },
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockResponse);
|
||||
const callArgs = mockFetch.mock.calls[0];
|
||||
expect(callArgs[1].method).toBe('DELETE');
|
||||
expect(callArgs[1].body).toBe(JSON.stringify({ id: '123' }));
|
||||
});
|
||||
|
||||
it('should handle GET request with query string', async () => {
|
||||
const mockResponse = {
|
||||
status: 'success',
|
||||
data: 'test data',
|
||||
};
|
||||
|
||||
mockFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => mockResponse,
|
||||
});
|
||||
|
||||
const result = await makeRequest({
|
||||
method: 'GET',
|
||||
path: '/test?param=value',
|
||||
apiKey,
|
||||
secretKey,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockResponse);
|
||||
const callArgs = mockFetch.mock.calls[0];
|
||||
expect(callArgs[0]).toBe('https://api.test.com/test?param=value');
|
||||
});
|
||||
});
|
||||
40
tests/unit/index.test.ts
Normal file
40
tests/unit/index.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Index exports test
|
||||
* This test ensures all exports from index.ts are accessible
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('Index exports', () => {
|
||||
it('should export IyzicoClient', async () => {
|
||||
const module = await import('../../src/index');
|
||||
expect(module.IyzicoClient).toBeDefined();
|
||||
expect(typeof module.IyzicoClient).toBe('function');
|
||||
});
|
||||
|
||||
it('should export all error classes', async () => {
|
||||
const module = await import('../../src/index');
|
||||
expect(module.IyzicoError).toBeDefined();
|
||||
expect(module.IyzicoRequestError).toBeDefined();
|
||||
expect(module.IyzicoResponseError).toBeDefined();
|
||||
expect(typeof module.IyzicoError).toBe('function');
|
||||
expect(typeof module.IyzicoRequestError).toBe('function');
|
||||
expect(typeof module.IyzicoResponseError).toBe('function');
|
||||
});
|
||||
|
||||
it('should export utility functions', async () => {
|
||||
const module = await import('../../src/index');
|
||||
expect(module.generateRandomNumber).toBeDefined();
|
||||
expect(module.generateRandomKey).toBeDefined();
|
||||
expect(typeof module.generateRandomNumber).toBe('function');
|
||||
expect(typeof module.generateRandomKey).toBe('function');
|
||||
});
|
||||
|
||||
it('should be importable', async () => {
|
||||
// Just verify the module can be imported (this covers index.ts line 1)
|
||||
const module = await import('../../src/index');
|
||||
expect(module).toBeDefined();
|
||||
expect(Object.keys(module).length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
53
tests/unit/utils.test.ts
Normal file
53
tests/unit/utils.test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Utility functions unit tests
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { generateRandomNumber, generateRandomKey } from '../../src/utils';
|
||||
|
||||
describe('generateRandomNumber', () => {
|
||||
it('should generate a number within the specified range', () => {
|
||||
const result = generateRandomNumber(1, 10);
|
||||
expect(result).toBeGreaterThanOrEqual(1);
|
||||
expect(result).toBeLessThanOrEqual(10);
|
||||
});
|
||||
|
||||
it('should use default values when no arguments provided', () => {
|
||||
const result = generateRandomNumber();
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThanOrEqual(100);
|
||||
});
|
||||
|
||||
it('should throw error when min is greater than max', () => {
|
||||
expect(() => generateRandomNumber(10, 5)).toThrow('Min value cannot be greater than max value');
|
||||
});
|
||||
|
||||
it('should handle equal min and max', () => {
|
||||
const result = generateRandomNumber(5, 5);
|
||||
expect(result).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateRandomKey', () => {
|
||||
it('should generate a non-empty string', () => {
|
||||
const result = generateRandomKey();
|
||||
expect(result).toBeTruthy();
|
||||
expect(typeof result).toBe('string');
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should generate different keys on each call', () => {
|
||||
const key1 = generateRandomKey();
|
||||
const key2 = generateRandomKey();
|
||||
expect(key1).not.toBe(key2);
|
||||
});
|
||||
|
||||
it('should generate keys that start with timestamp', () => {
|
||||
const result = generateRandomKey();
|
||||
const timestamp = Date.now();
|
||||
const keyTimestamp = parseInt(result.substring(0, 13));
|
||||
// Should be within 1 second of current timestamp
|
||||
expect(Math.abs(timestamp - keyTimestamp)).toBeLessThan(1000);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user