Skip to content

Commit 21f05ad

Browse files
Fix action destination middleware bug (#629)
* only transform destinations * add changeset * Add another test around mutating context * Update comment * Only add middleware to destination types
1 parent 6c35799 commit 21f05ad

File tree

3 files changed

+116
-3
lines changed

3 files changed

+116
-3
lines changed

.changeset/rich-icons-nail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-next': patch
3+
---
4+
5+
Fix bug where destination middleware were applying to other plugin types

packages/browser/src/plugins/remote-loader/__tests__/index.test.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as loader from '../../../lib/load-script'
2-
import { remoteLoader } from '..'
2+
import { ActionDestination, remoteLoader } from '..'
33
import { AnalyticsBrowser, LegacySettings } from '../../../browser'
44
import { InitOptions } from '../../../core/analytics'
55
import { Context } from '../../../core/context'
@@ -597,4 +597,105 @@ describe('Remote Loader', () => {
597597
}
598598
`)
599599
})
600+
601+
it('only applies destination middleware to destination actions', async () => {
602+
const validPlugin = {
603+
name: 'valid',
604+
version: '1.0.0',
605+
type: 'enrichment',
606+
load: () => {},
607+
isLoaded: () => true,
608+
track: (ctx: Context) => ctx,
609+
}
610+
611+
const cdnSettings: LegacySettings = {
612+
integrations: {},
613+
middlewareSettings: {
614+
routingRules: [
615+
{
616+
matchers: [
617+
{
618+
ir: '["=","event",{"value":"Item Impression"}]',
619+
type: 'fql',
620+
},
621+
],
622+
scope: 'destinations',
623+
target_type: 'workspace::project::destination::config',
624+
transformers: [[{ type: 'drop' }]],
625+
destinationName: 'oldValidName',
626+
},
627+
],
628+
},
629+
remotePlugins: [
630+
{
631+
name: 'valid',
632+
creationName: 'oldValidName',
633+
url: 'valid',
634+
libraryName: 'valid',
635+
settings: { foo: true },
636+
},
637+
],
638+
}
639+
640+
// @ts-expect-error not gonna return a script tag sorry
641+
jest.spyOn(loader, 'loadScript').mockImplementation((url: string) => {
642+
if (url === 'valid') {
643+
window['valid'] = jest.fn().mockImplementation(() => validPlugin)
644+
}
645+
646+
return Promise.resolve(true)
647+
})
648+
649+
const middleware = jest.fn().mockImplementation(() => true)
650+
651+
const plugins = await remoteLoader(cdnSettings, {}, {}, false, middleware)
652+
const plugin = plugins[0] as ActionDestination
653+
plugin.addMiddleware(middleware)
654+
await plugin.track(new Context({ type: 'track' }))
655+
expect(middleware).not.toHaveBeenCalled()
656+
})
657+
658+
it('non destination type plugins can modify the context', async () => {
659+
const validPlugin = {
660+
name: 'valid',
661+
version: '1.0.0',
662+
type: 'enrichment',
663+
load: () => {},
664+
isLoaded: () => true,
665+
track: (ctx: Context) => {
666+
ctx.event.name += 'bar'
667+
return ctx
668+
},
669+
}
670+
671+
const cdnSettings: LegacySettings = {
672+
integrations: {},
673+
remotePlugins: [
674+
{
675+
name: 'valid',
676+
creationName: 'valid',
677+
url: 'valid',
678+
libraryName: 'valid',
679+
settings: { foo: true },
680+
},
681+
],
682+
}
683+
684+
// @ts-expect-error not gonna return a script tag sorry
685+
jest.spyOn(loader, 'loadScript').mockImplementation((url: string) => {
686+
if (url === 'valid') {
687+
window['valid'] = jest.fn().mockImplementation(() => validPlugin)
688+
}
689+
690+
return Promise.resolve(true)
691+
})
692+
693+
const plugins = await remoteLoader(cdnSettings, {}, {}, false)
694+
const plugin = plugins[0] as ActionDestination
695+
const newCtx = await plugin.track(
696+
new Context({ type: 'track', name: 'foo' })
697+
)
698+
699+
expect(newCtx.event.name).toEqual('foobar')
700+
})
600701
})

packages/browser/src/plugins/remote-loader/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ export class ActionDestination implements Plugin {
4444
}
4545

4646
addMiddleware(...fn: DestinationMiddlewareFunction[]): void {
47-
this.middleware.push(...fn)
47+
if (this.type === 'destination') {
48+
this.middleware.push(...fn)
49+
}
4850
}
4951

5052
private async transform(ctx: Context): Promise<Context> {
@@ -72,7 +74,12 @@ export class ActionDestination implements Plugin {
7274
return async (ctx: Context): Promise<Context> => {
7375
if (!this.action[methodName]) return ctx
7476

75-
const transformedContext = await this.transform(ctx)
77+
let transformedContext: Context = ctx
78+
// Transformations only allowed for destination plugins. Other plugin types support mutating events.
79+
if (this.type === 'destination') {
80+
transformedContext = await this.transform(ctx)
81+
}
82+
7683
await this.action[methodName]!(transformedContext)
7784

7885
return ctx

0 commit comments

Comments
 (0)