Skip to content

Commit

Permalink
chore: update flatten params function and improve tests structure
Browse files Browse the repository at this point in the history
  • Loading branch information
vinayteki95 committed Feb 14, 2025
1 parent 5100e92 commit c200518
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 131 deletions.
9 changes: 6 additions & 3 deletions src/sources/adjust/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { TransformationError } = require('@rudderstack/integrations-lib');
const { TransformationError, isDefinedAndNotNull } = require('@rudderstack/integrations-lib');

/**
* Converts a raw timestamp to ISO 8601 date string format
Expand Down Expand Up @@ -35,13 +35,16 @@ const convertToISODate = (rawTimestamp) => {
* @description
* This function flattens an object containing array parameters into a simple key-value object
* with first element of array as value if it is an array, otherwise the value is returned as is
* In case of empty array, the value is returned as undefined
* In case of empty array, the key is removed from the output
*/
const flattenParams = (qParams) => {
const formattedOutput = {};
if (qParams) {
Object.entries(qParams).forEach(([key, value]) => {
formattedOutput[key] = Array.isArray(value) ? value[0] : value;
const finalValue = Array.isArray(value) ? value[0] : value;
if (isDefinedAndNotNull(finalValue)) {
formattedOutput[key] = finalValue;
}
});
}
return formattedOutput;
Expand Down
321 changes: 193 additions & 128 deletions src/sources/adjust/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,141 +2,206 @@ const { convertToISODate } = require('./utils');
const { TransformationError } = require('@rudderstack/integrations-lib');

describe('convertToISODate', () => {
// Converts valid numeric timestamp to ISO date string
it('should return ISO date string when given a valid numeric timestamp', () => {
const timestamp = 1633072800; // Example timestamp for 2021-10-01T00:00:00.000Z
const result = convertToISODate(timestamp);
expect(result).toBe('2021-10-01T07:20:00.000Z');
});

// Throws error for non-numeric string input
it('should throw TransformationError when given a non-numeric string', () => {
const invalidTimestamp = 'invalid';
expect(() => convertToISODate(invalidTimestamp)).toThrow(TransformationError);
});

// Converts valid numeric string timestamp to ISO date string
it('should convert valid numeric string timestamp to ISO date string', () => {
const rawTimestamp = '1633072800'; // Corresponds to 2021-10-01T00:00:00.000Z
const result = convertToISODate(rawTimestamp);
expect(result).toBe('2021-10-01T07:20:00.000Z');
});
const testCases = [
{
name: 'valid numeric timestamp',
input: 1633072800,
expected: '2021-10-01T07:20:00.000Z',
shouldThrow: false,
},
{
name: 'non-numeric string',
input: 'invalid',
shouldThrow: true,
errorType: TransformationError,
},
{
name: 'valid numeric string timestamp',
input: '1633072800',
expected: '2021-10-01T07:20:00.000Z',
shouldThrow: false,
},
{
name: 'object input',
input: {},
shouldThrow: true,
errorType: TransformationError,
},
{
name: 'array input',
input: [],
shouldThrow: true,
errorType: TransformationError,
},
{
name: 'null input',
input: null,
shouldThrow: true,
errorType: TransformationError,
},
{
name: 'undefined input',
input: undefined,
shouldThrow: true,
errorType: TransformationError,
},
{
name: 'huge timestamp that becomes invalid',
input: 999999999999999,
shouldThrow: true,
errorType: TransformationError,
},
];

// Throws error for non-number and non-string input
it('should throw error for non-number and non-string input', () => {
expect(() => convertToISODate({})).toThrow(TransformationError);
expect(() => convertToISODate([])).toThrow(TransformationError);
expect(() => convertToISODate(null)).toThrow(TransformationError);
expect(() => convertToISODate(undefined)).toThrow(TransformationError);
});

it('should throw error for timestamp that results in invalid date when multiplied', () => {
const hugeTimestamp = 999999999999999; // This will become invalid when multiplied by 1000
expect(() => convertToISODate(hugeTimestamp)).toThrow(TransformationError);
testCases.forEach(({ name, input, expected, shouldThrow, errorType }) => {
it(`should handle ${name}`, () => {
if (shouldThrow) {
expect(() => convertToISODate(input)).toThrow(errorType);
} else {
const result = convertToISODate(input);
expect(result).toBe(expected);
}
});
});
});

describe('flattenParams', () => {
const { flattenParams } = require('./utils');

it('should flatten object with array values to their first elements', () => {
const input = {
key1: ['value1'],
key2: ['value2'],
key3: [123],
};
const expected = {
key1: 'value1',
key2: 'value2',
key3: 123,
};
expect(flattenParams(input)).toEqual(expected);
});

it('should return empty object when input is null or undefined', () => {
expect(flattenParams(null)).toEqual({});
expect(flattenParams(undefined)).toEqual({});
});

it('should handle empty object input', () => {
expect(flattenParams({})).toEqual({});
});

it('should handle array with undefined or null first elements', () => {
const input = {
key1: [undefined],
key2: [null],
};
const expected = {
key1: undefined,
key2: null,
};
expect(flattenParams(input)).toEqual(expected);
});

it('should handle mixed type values in arrays', () => {
const input = {
number: [42],
string: ['test'],
boolean: [true],
object: [{ nested: 'value' }],
};
const expected = {
number: 42,
string: 'test',
boolean: true,
object: { nested: 'value' },
};
expect(flattenParams(input)).toEqual(expected);
});

it('should handle empty arrays as values', () => {
const input = {
key1: [],
key2: ['value'],
key3: [],
};
const expected = {
key1: undefined,
key2: 'value',
key3: undefined,
};
expect(flattenParams(input)).toEqual(expected);
});

it('should keep non-array values unchanged', () => {
const input = {
string: 'direct string',
number: 42,
boolean: true,
object: { test: 'value' },
array: ['first', 'second'],
};
const expected = {
string: 'direct string',
number: 42,
boolean: true,
object: { test: 'value' },
array: 'first',
};
expect(flattenParams(input)).toEqual(expected);
});
const testCases = [
{
name: 'flatten array values to first elements',
input: {
key1: ['value1'],
key2: ['value2'],
key3: [123],
},
expected: {
key1: 'value1',
key2: 'value2',
key3: 123,
},
},
{
name: 'handle null input',
input: null,
expected: {},
},
{
name: 'handle undefined input',
input: undefined,
expected: {},
},
{
name: 'handle empty object',
input: {},
expected: {},
},
{
name: 'ignore null/undefined array elements',
input: {
key1: [undefined],
key2: [null],
key3: [undefined, 'value'],
key4: [null, 'value'],
},
expected: {},
},
{
name: 'handle mixed type values in arrays',
input: {
number: [42],
string: ['test'],
boolean: [true],
object: [{ nested: 'value' }],
date: [new Date('2024-01-01')],
},
expected: {
number: 42,
string: 'test',
boolean: true,
object: { nested: 'value' },
date: new Date('2024-01-01'),
},
},
{
name: 'handle empty arrays',
input: {
key1: [],
key2: ['value'],
key3: [],
},
expected: {
key2: 'value',
},
},
{
name: 'keep non-array values unchanged',
input: {
string: 'direct string',
number: 42,
boolean: true,
object: { test: 'value' },
array: ['first', 'second'],
},
expected: {
string: 'direct string',
number: 42,
boolean: true,
object: { test: 'value' },
array: 'first',
},
},
{
name: 'handle mixed array and non-array values',
input: {
arrayValue: ['first'],
emptyArray: [],
directValue: 'string',
nullValue: null,
undefinedValue: undefined,
},
expected: {
arrayValue: 'first',
directValue: 'string',
},
},
{
name: 'handle nested arrays',
input: {
nested: [
[1, 2],
[3, 4],
],
mixed: [['a', 'b'], 'c'],
},
expected: {
nested: [1, 2],
mixed: ['a', 'b'],
},
},
{
name: 'handle special values in arrays',
input: {
nan: [NaN],
infinity: [Infinity],
negInfinity: [-Infinity],
zero: [0],
negZero: [-0],
},
expected: {
nan: NaN,
infinity: Infinity,
negInfinity: -Infinity,
zero: 0,
negZero: -0,
},
},
];

it('should handle mixed array and non-array values', () => {
const input = {
arrayValue: ['first'],
emptyArray: [],
directValue: 'string',
nullValue: null,
undefinedValue: undefined,
};
const expected = {
arrayValue: 'first',
emptyArray: undefined,
directValue: 'string',
nullValue: null,
undefinedValue: undefined,
};
expect(flattenParams(input)).toEqual(expected);
testCases.forEach(({ name, input, expected }) => {
it(`should ${name}`, () => {
expect(flattenParams(input)).toEqual(expected);
});
});
});

0 comments on commit c200518

Please sign in to comment.