lodash#shuffle TypeScript Examples

The following examples show how to use lodash#shuffle. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: team.ts    From fishbowl with MIT License 6 votes vote down vote up
export function teamsWithSequence(players: Players) {
  const shuffledPlayers = shuffle(players)
  const halfLength = Math.ceil(shuffledPlayers.length / 2)
  const redTeam = addTeamAndSequence(
    cloneDeep(shuffledPlayers).splice(0, halfLength),
    Team.Red
  )
  const blueTeam = addTeamAndSequence(
    cloneDeep(shuffledPlayers).splice(halfLength, shuffledPlayers.length),
    Team.Blue
  )
  return redTeam.concat(blueTeam)
}
Example #2
Source File: generateManifest.ts    From nft-maker-js with Do What The F*ck You Want To Public License 6 votes vote down vote up
export default async function (task: null | Task): Promise<void> {
  const { maxAttempts, uniques, editionSize } = resolveConfiguration()
  maxNumberOfAttempts = maxAttempts

  prepareOutputFolder()

  uniques.forEach((u: Image) => {
    if (validUnique(u)) {
      imageData.push(u)
    }
  })

  times(editionSize - uniques.length, () => {
    attempts++

    if (attempts == maxNumberOfAttempts) {
      fail(`Could not find a unique image after ${attempts} attempts.`)
    }

    imageData.push(createNewUniqueImage())
    attempts = 0
  })

  imageData = shuffle(imageData)
  imageData = assignTokenIds(imageData)

  fs.writeFileSync('./manifest.json', JSON.stringify(imageData, null, 2), {
    flag: 'w',
  })
}
Example #3
Source File: LokiCheatSheet.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
checkUserLabels = async () => {
    // Set example from user labels
    const provider: LokiLanguageProvider = this.props.datasource.languageProvider;
    if (provider.started) {
      const labels = provider.getLabelKeys() || [];
      const preferredLabel = PREFERRED_LABELS.find(l => labels.includes(l));
      if (preferredLabel) {
        const values = await provider.getLabelValues(preferredLabel);
        const userExamples = shuffle(values)
          .slice(0, EXAMPLES_LIMIT)
          .map(value => `{${preferredLabel}="${value}"}`);
        this.setState({ userExamples });
      }
    } else {
      this.scheduleUserLabelChecking();
    }
  };
Example #4
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
Badge = (props: IBadgeProps) => {
  const {
    color,
    tip,
    status: pStatus,
    text,
    size = 'default',
    breathing: pBreathing,
    className = '',
    showDot = true,
    onlyDot,
    suffixIcon,
    onlyText,
    onClick,
  } = props;
  const status = pStatus || 'default';
  const defaultBreath = { processing: true };
  const breathing = pBreathing === undefined && status ? defaultBreath[status] : pBreathing || false;

  const colorStyle = color ? { color, backgroundColor: colorToRgb(color, 0.1) } : undefined;

  const breathCls = breathing ? `badge-breathing badge-breathing-${shuffle([1, 2, 3])[0]}` : '';
  const hasClickOp = !!onClick;

  const cls = classnames(
    {
      'erda-badge': true,
      [`erda-badge-status-${status}`]: true,
      'bg-transparent': onlyText,
      [`badge-${size}`]: true,
      'inline-flex': true,
      'items-center': true,
      'rounded-sm': true,
      'only-dot': onlyDot,
      'badge-hover-active': hasClickOp,
    },
    className,
    breathCls,
  );

  return (
    <Tooltip title={tip}>
      <span style={onlyDot ? {} : colorStyle} className={`${cls}`} onClick={onClick}>
        {onlyDot || showDot ? (
          <span className="erda-badge-status-dot" style={color ? { backgroundColor: color } : {}}>
            <span className="erda-badge-status-breath" />
          </span>
        ) : null}
        {!onlyDot || onlyText ? (
          <span className="erda-badge-status-text flex-h-center">
            {text} {suffixIcon ? <ErdaIcon type={suffixIcon} /> : null}
          </span>
        ) : null}
      </span>
    </Tooltip>
  );
}
Example #5
Source File: generateManifest.ts    From nft-maker-js with Do What The F*ck You Want To Public License 5 votes vote down vote up
export function getRandomWeightedTrait(
  trait: string,
  existing: Image
): ImageDefinition {
  const { traits } = resolveConfiguration()

  const category: TraitCategory = find(
    traits,
    (t: TraitCategory) => t.name == trait
  )

  // Find compatible category trait items for the existing object
  // If it's the first time to find a trait we'll just grab
  // whichever one we want since there's nothing to check.
  let items: Trait[] = category.items

  items = items.filter((trait: Trait) => {
    return traitIsCompatibleWithCurrentImage(category, trait, existing)
  })

  if (items.length == 0) {
    fail(
      `Could not generate unique image because there are no compatible traits for ${trait}`
    )
  }

  shuffle(items)

  let choices = items.reduce((carry: any, item, key) => {
    return carry.concat(new Array(item.weight).fill(key))
  }, [])

  // Shuffle the choices
  shuffle(choices)

  // Pull a random
  let choice = Math.floor(Math.random() * (choices.length - 1))
  let index = choices[choice]

  return {
    name: items[index].name,
    image: items[index].image || items[index].name,
  }
}
Example #6
Source File: TeamCredits.tsx    From nextclade with MIT License 5 votes vote down vote up
export function TeamCredits() {
  const maintainerComponents = useMemo(
    () => shuffle(maintainers).map((maintainer) => <Maintainer key={maintainer.name} maintainer={maintainer} />),
    [],
  )

  const contributorComponents = useMemo(
    () =>
      shuffle(contributors).map((contributor) => (
        <TeamCreditsContributor key={contributor.login} contributor={contributor} />
      )),
    [],
  )

  return (
    <Row noGutters>
      <Col>
        <Row noGutters>
          <Col className="d-flex text-center">
            <TeamCreditsH1>
              {`${PROJECT_NAME} is a part of `}
              <NextstrainLogo width="20px" height="20px" className="mx-1" />
              <LinkExternal href="https://nextstrain.org">
                <span>{'Nextstrain project'}</span>
              </LinkExternal>
              <span>{`. ${PROJECT_NAME} is maintained by: `}</span>
            </TeamCreditsH1>
          </Col>
        </Row>

        <Row noGutters>
          <FlexCol>{maintainerComponents}</FlexCol>
        </Row>

        <Row noGutters>
          <Col>
            <TeamCreditsH1 className="text-center">{'We are thankful to our contributors: '}</TeamCreditsH1>
            <FlexContributors>{contributorComponents}</FlexContributors>
          </Col>
        </Row>
      </Col>
    </Row>
  )
}
Example #7
Source File: Deck.test.ts    From excalideck with MIT License 4 votes vote down vote up
describe("Hash.deck uniquely identifies a deck's printable area, common elements (with their sort order), and slides (with their sort order)", () => {
    it("case: different printable area, different hash", () => {
        const deck0: Deck = {
            commonExcalidrawElements: makeRandomExcalidrawElements(),
            printableArea: makeRandomPrintableArea(),
            slides: makeRandomSlides(),
        };
        const deck1: Deck = {
            ...deck0,
            printableArea: makeRandomPrintableArea(),
        };

        // Exercise + verify
        expect(Hash.deck(deck0)).not.toEqual(Hash.deck(deck1));
    });

    it("case: different common elements, different hash", () => {
        // Setup
        const deck0: Deck = {
            commonExcalidrawElements: makeRandomExcalidrawElements(),
            printableArea: makeRandomPrintableArea(),
            slides: makeRandomSlides(),
        };
        const deck1: Deck = {
            ...deck0,
            commonExcalidrawElements: makeRandomExcalidrawElements(),
        };

        // Exercise + verify
        expect(Hash.deck(deck0)).not.toEqual(Hash.deck(deck1));
    });

    it("case: different sorting of common elements, different hash", () => {
        // Setup
        const deck0: Deck = {
            commonExcalidrawElements: makeRandomExcalidrawElements(),
            printableArea: makeRandomPrintableArea(),
            slides: makeRandomSlides(),
        };
        const deck1: Deck = {
            ...deck0,
            commonExcalidrawElements: shuffle(deck0.commonExcalidrawElements),
        };

        // Exercise + verify
        expect(Hash.deck(deck0)).not.toEqual(Hash.deck(deck1));
    });

    it("case: different slides, different hash", () => {
        const deck0: Deck = {
            commonExcalidrawElements: makeRandomExcalidrawElements(),
            printableArea: makeRandomPrintableArea(),
            slides: makeRandomSlides(),
        };
        const deck1: Deck = {
            ...deck0,
            slides: makeRandomSlides(),
        };

        // Exercise + verify
        expect(Hash.deck(deck0)).not.toEqual(Hash.deck(deck1));
    });

    it("case: different sorting of slides, different hash", () => {
        const deck0: Deck = {
            commonExcalidrawElements: makeRandomExcalidrawElements(),
            printableArea: makeRandomPrintableArea(),
            slides: makeRandomSlides(),
        };
        const deck1: Deck = {
            ...deck0,
            slides: shuffle(deck0.slides),
        };

        // Exercise + verify
        expect(Hash.deck(deck0)).not.toEqual(Hash.deck(deck1));
    });

    it("case: same everything, same hash", () => {
        const deck0: Deck = {
            commonExcalidrawElements: makeRandomExcalidrawElements(),
            printableArea: makeRandomPrintableArea(),
            slides: makeRandomSlides(),
        };
        const deck1: Deck = {
            ...deck0,
        };

        // Exercise + verify
        expect(Hash.deck(deck0)).toEqual(Hash.deck(deck1));
    });
});
Example #8
Source File: Slide.test.ts    From excalideck with MIT License 4 votes vote down vote up
describe("Hash.slide uniquely identifies a slide configuration and its excalidraw elements (with their sort order)", () => {
    it("case: different shouldRender, different hash", () => {
        // Setup
        const slide0: Slide = {
            id: "slide0",
            shouldRender: true,
            shouldRenderWithCommonExcalidrawElements: true,
            excalidrawElements: makeRandomExcalidrawElements(),
        };
        const slide1: Slide = {
            ...slide0,
            id: "slide1",
            shouldRender: false,
        };

        // Exercise + verify
        expect(Hash.slide(slide0)).not.toEqual(Hash.slide(slide1));
    });

    it("case: different shouldRenderWithCommonExcalidrawElements, different hash", () => {
        // Setup
        const slide0: Slide = {
            id: "slide0",
            shouldRender: true,
            shouldRenderWithCommonExcalidrawElements: true,
            excalidrawElements: makeRandomExcalidrawElements(),
        };
        const slide1: Slide = {
            ...slide0,
            id: "slide1",
            shouldRenderWithCommonExcalidrawElements: false,
        };

        // Exercise + verify
        expect(Hash.slide(slide0)).not.toEqual(Hash.slide(slide1));
    });

    it("case: inverted shouldRender and shouldRenderWithCommonExcalidrawElements, different hash", () => {
        // Setup
        const slide0: Slide = {
            id: "slide0",
            shouldRender: true,
            shouldRenderWithCommonExcalidrawElements: false,
            excalidrawElements: makeRandomExcalidrawElements(),
        };
        const slide1: Slide = {
            ...slide0,
            id: "slide1",
            shouldRender: false,
            shouldRenderWithCommonExcalidrawElements: true,
        };

        // Exercise + verify
        expect(Hash.slide(slide0)).not.toEqual(Hash.slide(slide1));
    });

    it("case: different excalidraw elements, different hash", () => {
        // Setup
        const slide0: Slide = {
            id: "slide0",
            shouldRender: true,
            shouldRenderWithCommonExcalidrawElements: false,
            excalidrawElements: makeRandomExcalidrawElements(),
        };
        const slide1: Slide = {
            ...slide0,
            id: "slide1",
            excalidrawElements: makeRandomExcalidrawElements(),
        };

        // Exercise + verify
        expect(Hash.slide(slide0)).not.toEqual(Hash.slide(slide1));
    });

    it("case: different sorting of excalidraw elements, different hash", () => {
        // Setup
        const slide0: Slide = {
            id: "slide0",
            shouldRender: true,
            shouldRenderWithCommonExcalidrawElements: false,
            excalidrawElements: makeRandomExcalidrawElements(),
        };
        const slide1: Slide = {
            ...slide0,
            id: "slide1",
            excalidrawElements: shuffle(slide0.excalidrawElements),
        };

        // Exercise + verify
        expect(Hash.slide(slide0)).not.toEqual(Hash.slide(slide1));
    });

    it("case: same everything, same hash", () => {
        // Setup
        const slide0: Slide = {
            id: "slide0",
            shouldRender: true,
            shouldRenderWithCommonExcalidrawElements: false,
            excalidrawElements: makeRandomExcalidrawElements(),
        };
        const slide1: Slide = {
            ...slide0,
            id: "slide1",
        };

        // Exercise + verify
        expect(Hash.slide(slide0)).toEqual(Hash.slide(slide1));
    });
});
Example #9
Source File: index.tsx    From analytics-next with MIT License 4 votes vote down vote up
export default function Home(): React.ReactElement {
  const [analytics, setAnalytics] = useState<Analytics | undefined>(undefined)

  const writeKeyRef = useRef<HTMLInputElement>()
  const cdnURLRef = useRef<HTMLInputElement>()

  const {
    analytics: analyticsBrowser,
    cdnURL,
    setCDNUrl,
    writeKey,
    setWriteKey,
  } = useAnalytics()

  const mockTraits = (): any => {
    const fakerFns = [
      ...Object.entries(faker.name),
      ...Object.entries(faker.commerce),
      ...Object.entries(faker.internet),
      ...Object.entries(faker.company),
    ]

    const randomStuff = shuffle(fakerFns).slice(
      0,
      Math.round(Math.random() * 10) + 3
    )

    const event = randomStuff.reduce((ev, [name, fn]) => {
      return {
        [name]: fn(),
        ...ev,
      }
    }, {})

    return event
  }

  const [event, setEvent] = React.useState({} as ReturnType<typeof mockTraits>)
  const [ctx, setCtx] = React.useState<Context>()

  useEffect(() => {
    async function handleAnalyticsLoading(browser: AnalyticsBrowser) {
      try {
        const [response, ctx] = await browser
        setCtx(ctx)
        setAnalytics(response)
        setEvent(mockTraits())
        // @ts-ignore
        window.analytics = response
      } catch (err) {
        console.error(err)
        setCtx(undefined)
        setAnalytics(undefined)
        setEvent({})
      }
    }
    handleAnalyticsLoading(analyticsBrowser)
  }, [analyticsBrowser])

  const track = async (e: any) => {}

  const identify = async (e: any) => {}

  return (
    <div className="drac-spacing-md-x">
      <Head>
        <title>Tester App</title>
      </Head>

      <h1 className="drac-text">
        <span className="drac-text-purple-cyan">Analytics Next</span> Tester
      </h1>

      <form
        onSubmit={(e) => {
          e.preventDefault()
          setWriteKey(writeKeyRef!.current!.value)
          setCDNUrl(cdnURLRef!.current!.value)
        }}
      >
        <label>
          CDN:
          <input type="text" ref={cdnURLRef} defaultValue={cdnURL} />
        </label>
        <br />
        <label>
          Writekey:
          <input type="text" ref={writeKeyRef} defaultValue={writeKey} />
        </label>
        <input type="submit" value="Load Analytics" />
      </form>

      <main
        className="drac-box"
        style={{
          display: 'flex',
          justifyContent: 'space-around',
          flexWrap: 'wrap',
          alignItems: 'flex-start',
        }}
      >
        <div style={{ flex: 1 }}>
          <h2 className="drac-text">Event</h2>
          <form>
            <div
              style={{
                borderWidth: '1px',
                borderStyle: 'solid',
                marginTop: 20,
                marginBottom: 20,
              }}
              className="drac-box drac-border-purple"
            >
              <Editor
                value={event}
                onValueChange={(event) => setEvent(JSON.parse(event))}
                highlight={(code) =>
                  highlight(JSON.stringify(code, undefined, 2), languages.json)
                }
                padding={10}
                style={{
                  fontFamily: '"Fira code", "Fira Mono", monospace',
                  fontSize: 12,
                }}
              />
            </div>
            <button
              className="drac-btn drac-bg-yellow-pink"
              style={{
                marginRight: 20,
              }}
              onClick={(e) => {
                e.preventDefault()
                analytics
                  .track(event?.event ?? 'Track Event', event)
                  .then(setCtx)
              }}
            >
              Track
            </button>
            <button
              style={{
                marginRight: 20,
              }}
              className="drac-btn drac-bg-purple-cyan"
              onClick={(e) => {
                e.preventDefault()
                const { userId = 'Test User', ...traits } = event
                analytics.identify(userId, traits).then(setCtx)
              }}
            >
              Identify
            </button>

            <button
              id="shuffle"
              className="drac-btn drac-bg-purple"
              onClick={(e) => {
                e.preventDefault()
                setEvent(mockTraits())
              }}
            >
              Shuffle Event
            </button>
          </form>
        </div>

        <div className="drac-box drac-spacing-lg-x" style={{ flex: 1 }}>
          <h2 className="drac-text">Result</h2>
          {ctx && (
            <JSONTree
              theme={jsontheme}
              sortObjectKeys
              data={ctx.event}
              invertTheme={false}
            />
          )}
        </div>
      </main>

      <div
        style={{
          display: 'flex',
          alignItems: 'flex-start',
        }}
      >
        <div className="drac-box drac-spacing-md-y" style={{ flex: 1 }}>
          <h2 className="drac-text">Logs</h2>
          <Table
            columns={[
              {
                title: 'Level',
                dataIndex: 'level',
                key: 'level',
              },
              {
                title: 'Message',
                dataIndex: 'message',
                key: 'message',
              },
              {
                title: 'Extras',
                dataIndex: 'extras',
                key: 'extras',
                width: '100%',
                render(_val, logMessage) {
                  const json = logMessage.extras ?? {}
                  return (
                    <JSONTree
                      shouldExpandNode={(_keyName, _data, level) => level > 0}
                      theme={jsontheme}
                      data={json}
                      invertTheme={false}
                    />
                  )
                },
              },
            ]}
            data={ctx?.logs() ?? []}
          />
        </div>

        <div className="drac-box drac-spacing-md-y" style={{ flex: 1 }}>
          <h2 className="drac-text">Stats</h2>
          <Table
            columns={[
              {
                title: 'Metric',
                dataIndex: 'metric',
                key: 'metric',
              },
              {
                title: 'Value',
                dataIndex: 'value',
                key: 'value',
              },
              {
                title: 'Type',
                dataIndex: 'type',
                key: 'type',
              },
              {
                title: 'Tags',
                dataIndex: 'tags',
                key: 'tags',
                width: '100%',
                render(_val, metric) {
                  return JSON.stringify(metric.tags)
                },
              },
            ]}
            data={ctx?.stats.metrics ?? []}
          />
        </div>
      </div>
    </div>
  )
}
Example #10
Source File: extension-flushing.test.ts    From analytics-next with MIT License 4 votes vote down vote up
describe('Plugin flushing', () => {
  test('ensures `before` plugins are run', async () => {
    const eq = new EventQueue()
    const queue = new PriorityQueue(1, [])

    eq.queue = queue

    await eq.register(
      Context.system(),
      {
        ...testPlugin,
        type: 'before',
      },
      ajs
    )

    const flushed = await eq.dispatch(fruitBasket)
    expect(flushed.logs().map((l) => l.message)).toContain('Delivered')

    await eq.register(
      Context.system(),
      {
        ...testPlugin,
        name: 'Faulty before',
        type: 'before',
        track: () => {
          throw new Error('aaay')
        },
      },
      ajs
    )

    const failedFlush: Context = await eq
      .dispatch(
        new Context({
          type: 'track',
        })
      )
      .catch((ctx) => ctx)

    const messages = failedFlush.logs().map((l) => l.message)
    expect(messages).not.toContain('Delivered')
  })

  test('atempts `enrichment` plugins', async () => {
    const eq = new EventQueue()

    await eq.register(
      Context.system(),
      {
        ...testPlugin,
        name: 'Faulty enrichment',
        type: 'enrichment',
        track: () => {
          throw new Error('aaay')
        },
      },
      ajs
    )

    const flushed = await eq.dispatch(
      new Context({
        type: 'track',
      })
    )

    const messages = flushed.logs().map((l) => l.message)
    expect(messages).toContain('Delivered')
  })

  test('attempts `destination` plugins', async () => {
    const eq = new EventQueue()

    const amplitude: Plugin = {
      ...testPlugin,
      name: 'Amplitude',
      type: 'destination',
      track: async () => {
        throw new Error('Boom!')
      },
    }

    const fullstory: Plugin = {
      ...testPlugin,
      name: 'FullStory',
      type: 'destination',
    }

    await eq.register(Context.system(), amplitude, ajs)
    await eq.register(Context.system(), fullstory, ajs)

    const flushed = await eq.dispatch(
      new Context({
        type: 'track',
      })
    )

    const messages = flushed
      .logs()
      .map((l) => ({ message: l.message, extras: l.extras }))

    expect(messages).toMatchInlineSnapshot(`
      Array [
        Object {
          "extras": undefined,
          "message": "Dispatching",
        },
        Object {
          "extras": Object {
            "plugin": "Amplitude",
          },
          "message": "plugin",
        },
        Object {
          "extras": Object {
            "plugin": "FullStory",
          },
          "message": "plugin",
        },
        Object {
          "extras": Object {
            "error": [Error: Boom!],
            "plugin": "Amplitude",
          },
          "message": "plugin Error",
        },
        Object {
          "extras": Object {
            "type": "track",
          },
          "message": "Delivered",
        },
      ]
    `)
  })

  test('attempts `after` plugins', async () => {
    const eq = new EventQueue()

    const afterFailed: Plugin = {
      ...testPlugin,
      name: 'after-failed',
      type: 'after',
      track: async () => {
        throw new Error('Boom!')
      },
    }

    const after: Plugin = {
      ...testPlugin,
      name: 'after',
      type: 'after',
    }

    await eq.register(Context.system(), afterFailed, ajs)
    await eq.register(Context.system(), after, ajs)

    const flushed = await eq.dispatch(
      new Context({
        type: 'track',
      })
    )

    const messages = flushed
      .logs()
      .map((l) => ({ message: l.message, extras: l.extras }))
    expect(messages).toMatchInlineSnapshot(`
      Array [
        Object {
          "extras": undefined,
          "message": "Dispatching",
        },
        Object {
          "extras": Object {
            "plugin": "after-failed",
          },
          "message": "plugin",
        },
        Object {
          "extras": Object {
            "plugin": "after",
          },
          "message": "plugin",
        },
        Object {
          "extras": Object {
            "error": [Error: Boom!],
            "plugin": "after-failed",
          },
          "message": "plugin Error",
        },
        Object {
          "extras": Object {
            "type": "track",
          },
          "message": "Delivered",
        },
      ]
    `)
  })

  test('runs `enrichment` and `before` inline', async () => {
    const eq = new EventQueue()

    await eq.register(
      Context.system(),
      {
        ...testPlugin,
        name: 'Kiwi',
        type: 'enrichment',
        track: async (ctx) => {
          ctx.updateEvent('properties.kiwi', '?')
          return ctx
        },
      },
      ajs
    )

    await eq.register(
      Context.system(),
      {
        ...testPlugin,
        name: 'Watermelon',
        type: 'enrichment',
        track: async (ctx) => {
          ctx.updateEvent('properties.watermelon', '?')
          return ctx
        },
      },
      ajs
    )

    await eq.register(
      Context.system(),
      {
        ...testPlugin,
        name: 'Before',
        type: 'before',
        track: async (ctx) => {
          ctx.stats.increment('before')
          return ctx
        },
      },
      ajs
    )

    const flushed = await eq.dispatch(
      new Context({
        type: 'track',
      })
    )

    expect(flushed.event.properties).toEqual({
      watermelon: '?',
      kiwi: '?',
    })

    expect(flushed.stats.metrics.map((m) => m.metric)).toContain('before')
  })

  test('respects execution order', async () => {
    const eq = new EventQueue()

    let trace = 0

    const before: Plugin = {
      ...testPlugin,
      name: 'Before',
      type: 'before',
      track: async (ctx) => {
        trace++
        expect(trace).toBe(1)
        return ctx
      },
    }

    const enrichment: Plugin = {
      ...testPlugin,
      name: 'Enrichment',
      type: 'enrichment',
      track: async (ctx) => {
        trace++
        expect(trace === 2 || trace === 3).toBe(true)
        return ctx
      },
    }

    const enrichmentTwo: Plugin = {
      ...testPlugin,
      name: 'Enrichment 2',
      type: 'enrichment',
      track: async (ctx) => {
        trace++
        expect(trace === 2 || trace === 3).toBe(true)
        return ctx
      },
    }

    const destination: Plugin = {
      ...testPlugin,
      name: 'Destination',
      type: 'destination',
      track: async (ctx) => {
        trace++
        expect(trace).toBe(4)
        return ctx
      },
    }

    // shuffle plugins so we can verify order
    const plugins = shuffle([before, enrichment, enrichmentTwo, destination])
    for (const xt of plugins) {
      await eq.register(Context.system(), xt, ajs)
    }

    await eq.dispatch(
      new Context({
        type: 'track',
      })
    )

    expect(trace).toBe(4)
  })
})