Skip to content

Commit

Permalink
fix: handle null as the first argument in identify (#950)
Browse files Browse the repository at this point in the history
  • Loading branch information
oscb authored Oct 10, 2023
1 parent 1c04276 commit c0dadc7
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-tables-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@segment/analytics-next': patch
---

Fixes calls to .identify() with null as id
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,31 @@ describe(resolveUserArguments, () => {
expect(traits).toEqual(userTraits)
expect(options).toEqual({})
})

it('should accept (undefined, traits)', () => {
user.reset()
const [id, traits, options] = resolver(undefined, userTraits)
expect(traits).toEqual(userTraits)
expect(options).toEqual({})
expect(id).toEqual(null)
})

it('should accept (null, traits) with unknown identity', () => {
user.reset()
const [id, traits, options] = resolver(null, userTraits)
expect(traits).toEqual(userTraits)
expect(options).toEqual({})
expect(id).toEqual(null)
})

it('should accept (null, traits) when identity is set', () => {
user.reset()
user.identify('something')
const [id, traits, options] = resolver(null, userTraits)
expect(traits).toEqual(userTraits)
expect(options).toEqual({})
expect(id).toEqual('something')
})
})

describe(resolveAliasArguments, () => {
Expand Down
58 changes: 46 additions & 12 deletions packages/browser/src/core/arguments-resolver/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,56 @@ export const resolveUserArguments = <T extends Traits, U extends User>(
user: U
): ResolveUser<T> => {
return (...args): ReturnType<ResolveUser<T>> => {
let id: string | ID | null = null
id = args.find(isString) ?? args.find(isNumber)?.toString() ?? user.id()

const objects = args.filter((obj) => {
if (id === null) {
return isPlainObject(obj)
const values: {
id?: ID
traits?: T | null
options?: Options
callback?: Callback
} = {}
// It's a stack so it's reversed so that we go through each of the expected arguments
const orderStack: Array<keyof typeof values> = [
'callback',
'options',
'traits',
'id',
]

// Read each argument and eval the possible values here
for (const arg of args) {
let current = orderStack.pop()
if (current === 'id') {
if (isString(arg) || isNumber(arg)) {
values.id = arg.toString()
continue
}
if (arg === null || arg === undefined) {
continue
}
// First argument should always be the id, if it is not a valid value we can skip it
current = orderStack.pop()
}
return isPlainObject(obj) || obj === null
}) as Array<Traits | null>

const traits = (objects[0] ?? {}) as T
const opts = (objects[1] ?? {}) as Options
// Traits and Options
if (
(current === 'traits' || current === 'options') &&
(arg === null || arg === undefined || isPlainObject(arg))
) {
values[current] = arg as T
}

const resolvedCallback = args.find(isFunction) as Callback | undefined
// Callback
if (isFunction(arg)) {
values.callback = arg as Callback
break // This is always the last argument
}
}

return [id, traits, opts, resolvedCallback]
return [
values.id ?? user.id(),
(values.traits ?? {}) as T,
values.options ?? {},
values.callback,
]
}
}

Expand Down

0 comments on commit c0dadc7

Please sign in to comment.