Skip to content

Commit

Permalink
More PR Feedback
Browse files Browse the repository at this point in the history
- Use PascalCase for default global prefix
- Fix typos
- Rejig tests to create elements a little more like what we would write
  in real components
  • Loading branch information
BPScott committed Sep 5, 2019
1 parent 76a7808 commit 7669582
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 66 deletions.
8 changes: 4 additions & 4 deletions src/utilities/unique-id/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import {useContext, useRef} from 'react';
import {UniqueIdFactoryContext} from './context';

/**
* Returns a unique id that remains consistent across multiple rerenders of the
* Returns a unique id that remains consistent across multiple re-renders of the
* same hook
* @param prefix Defines a prefix for the ID. You probably want to set this to
* the name of the component you're calling `useUniqueId` in.
* @param overrideId Defines a fixed value to use instead of generating a unique
* ID. Useful for components that allow consumers to specify a fixed ID.
* ID. Useful for components that allow consumers to specify their own ID.
*/
export function useUniqueId(prefix = '', overrideId = '') {
const idFactory = useContext(UniqueIdFactoryContext);

// By using a ref to store the uniqueId for each incovation of the hook and
// By using a ref to store the uniqueId for each invocation of the hook and
// checking that it is not already populated we ensure that we don't generate
// a new ID on ever rerender of a component.
// a new ID on every re-render of a component.
const uniqueIdRef = useRef<string | null>(null);

if (!idFactory) {
Expand Down
110 changes: 62 additions & 48 deletions src/utilities/unique-id/tests/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ function TestHarness({children}: {children: React.ReactNode}) {
return <React.Fragment>{children}</React.Fragment>;
}

const Component1 = () => <React.Fragment>{useUniqueId()}</React.Fragment>;
const Component2 = () => <React.Fragment>{useUniqueId()}</React.Fragment>;
const Component3 = () => <React.Fragment>{useUniqueId()}</React.Fragment>;
const Component1 = () => <div id={useUniqueId()} />;
const Component2 = () => <div id={useUniqueId()} />;
const Component3 = () => <div id={useUniqueId()} />;

const HasPrefix1 = () => <React.Fragment>{useUniqueId('a')}</React.Fragment>;
const HasPrefix2 = () => <React.Fragment>{useUniqueId('a')}</React.Fragment>;
const HasPrefix3 = () => <React.Fragment>{useUniqueId('a')}</React.Fragment>;
const HasPrefix4 = () => <React.Fragment>{useUniqueId('b')}</React.Fragment>;
const HasPrefix1 = () => <div id={useUniqueId('A')} />;
const HasPrefix2 = () => <div id={useUniqueId('A')} />;
const HasPrefix3 = () => <div id={useUniqueId('A')} />;
const HasPrefix4 = () => <div id={useUniqueId('B')} />;

describe('useUniqueId', () => {
it('returns unique IDs across a single component', () => {
Expand All @@ -28,13 +28,12 @@ describe('useUniqueId', () => {
</TestHarness>,
);

expect(harness.findAll(Component1)[0].html()).toStrictEqual('polaris-1');
expect(harness.findAll(Component1)[1].html()).toStrictEqual('polaris-2');
expect(harness.findAll(Component1)[2].html()).toStrictEqual('polaris-3');

expect(harness.findAll(HasPrefix1)[0].html()).toStrictEqual('polaris-a1');
expect(harness.findAll(HasPrefix1)[1].html()).toStrictEqual('polaris-a2');
expect(harness.findAll(HasPrefix1)[2].html()).toStrictEqual('polaris-a3');
expect(harness.findAll('div')[0]).toHaveReactProps({id: 'Polaris1'});
expect(harness.findAll('div')[1]).toHaveReactProps({id: 'Polaris2'});
expect(harness.findAll('div')[2]).toHaveReactProps({id: 'Polaris3'});
expect(harness.findAll('div')[3]).toHaveReactProps({id: 'PolarisA1'});
expect(harness.findAll('div')[4]).toHaveReactProps({id: 'PolarisA2'});
expect(harness.findAll('div')[5]).toHaveReactProps({id: 'PolarisA3'});
});

it('returns unique IDs across multiple components', () => {
Expand All @@ -50,41 +49,39 @@ describe('useUniqueId', () => {
</TestHarness>,
);

expect(harness.find(Component1)!.html()).toStrictEqual('polaris-1');
expect(harness.find(Component2)!.html()).toStrictEqual('polaris-2');
expect(harness.find(Component3)!.html()).toStrictEqual('polaris-3');

expect(harness.find(HasPrefix1)!.html()).toStrictEqual('polaris-a1');
expect(harness.find(HasPrefix2)!.html()).toStrictEqual('polaris-a2');
expect(harness.find(HasPrefix3)!.html()).toStrictEqual('polaris-a3');
expect(harness.find(HasPrefix4)!.html()).toStrictEqual('polaris-b1');
expect(harness.findAll('div')[0]).toHaveReactProps({id: 'Polaris1'});
expect(harness.findAll('div')[1]).toHaveReactProps({id: 'Polaris2'});
expect(harness.findAll('div')[2]).toHaveReactProps({id: 'Polaris3'});
expect(harness.findAll('div')[3]).toHaveReactProps({id: 'PolarisA1'});
expect(harness.findAll('div')[4]).toHaveReactProps({id: 'PolarisA2'});
expect(harness.findAll('div')[5]).toHaveReactProps({id: 'PolarisA3'});
expect(harness.findAll('div')[6]).toHaveReactProps({id: 'PolarisB1'});
});

it('increments multiple IDs within the same component', () => {
const HasMultipleIds = () => (
<React.Fragment>
{useUniqueId()} :: {useUniqueId()}
</React.Fragment>
<div id={useUniqueId()} title={useUniqueId()} />
);

const harness = mountWithApp(<HasMultipleIds />);

expect(harness.html()).toStrictEqual('polaris-1 :: polaris-2');
expect(harness.find('div')).toHaveReactProps({
id: 'Polaris1',
title: 'Polaris2',
});
});

it('uses an override if specified', () => {
const HasOverride = () => (
<React.Fragment>{useUniqueId('', 'overridden')}</React.Fragment>
);
const HasOverride = () => <div id={useUniqueId('', 'overridden')} />;

const harness = mountWithApp(<HasOverride />);

expect(harness.html()).toStrictEqual('overridden');
expect(harness.find('div')).toHaveReactProps({id: 'overridden'});
});

it('uses an override if specified and the override does not interupt the count', () => {
const HasOverride = ({idOverride}: {idOverride?: string}) => (
<React.Fragment>{useUniqueId('', idOverride)}</React.Fragment>
<div id={useUniqueId('', idOverride)} />
);

const harness = mountWithApp(
Expand All @@ -95,16 +92,14 @@ describe('useUniqueId', () => {
</TestHarness>,
);

expect(harness.findAll(HasOverride)[0].html()).toStrictEqual('polaris-1');
expect(harness.findAll(HasOverride)[1].html()).toStrictEqual('overridden');
expect(harness.findAll(HasOverride)[2].html()).toStrictEqual('polaris-2');
expect(harness.findAll('div')[0]).toHaveReactProps({id: 'Polaris1'});
expect(harness.findAll('div')[1]).toHaveReactProps({id: 'overridden'});
expect(harness.findAll('div')[2]).toHaveReactProps({id: 'Polaris2'});
});

it('keeps the same ID across multiple rerenders', () => {
const HasProp = ({info}: {info: string}) => (
<React.Fragment>
{info} :: {useUniqueId()}
</React.Fragment>
<div id={useUniqueId()} title={info} />
);

const ReRenderingTestHarness = () => {
Expand All @@ -124,19 +119,23 @@ describe('useUniqueId', () => {

const harness = mountWithApp(<ReRenderingTestHarness />);

expect(harness.find(HasProp)!.html()).toStrictEqual('count1 :: polaris-1');
expect(harness.findAll('div')[0]).toHaveReactProps({
title: 'count1',
id: 'Polaris1',
});

harness.find('button')!.trigger('onClick');

expect(harness.find(HasProp)!.html()).toStrictEqual('count2 :: polaris-1');
expect(harness.findAll('div')[0]).toHaveReactProps({
title: 'count2',
id: 'Polaris1',
});
});

it('updates the ID if the overridden ID changes', () => {
type HasPropProps = {info: string; idOverride?: string};
const HasProp = ({info, idOverride}: HasPropProps) => (
<React.Fragment>
{info} :: {useUniqueId('', idOverride)}
</React.Fragment>
<div id={useUniqueId('', idOverride)} title={info} />
);

const ReRenderingTestHarness = () => {
Expand All @@ -147,7 +146,7 @@ describe('useUniqueId', () => {
);

// eslint-disable-next-line shopify/jest/no-if
const override = count % 2 === 0 ? `override-${count}` : undefined;
const override = count % 2 === 0 ? `Override${count}` : undefined;

return (
<React.Fragment>
Expand All @@ -160,23 +159,38 @@ describe('useUniqueId', () => {
const harness = mountWithApp(<ReRenderingTestHarness />);

// Initially we use an incremental id
expect(harness.find(HasProp)!.html()).toStrictEqual('count1 :: polaris-1');
expect(harness.find('div')).toHaveReactProps({
title: 'count1',
id: 'Polaris1',
});

// But then we set an override id, so it should use that
harness.find('button')!.trigger('onClick');
expect(harness.find(HasProp)!.html()).toStrictEqual('count2 :: override-2');
expect(harness.find('div')).toHaveReactProps({
title: 'count2',
id: 'Override2',
});

// Then on the next render we don't set an override id, so we should go back
// to using the incremental id
harness.find('button')!.trigger('onClick');
expect(harness.find(HasProp)!.html()).toStrictEqual('count3 :: polaris-1');
expect(harness.find('div')).toHaveReactProps({
title: 'count3',
id: 'Polaris1',
});

// Back to setting an override id
harness.find('button')!.trigger('onClick');
expect(harness.find(HasProp)!.html()).toStrictEqual('count4 :: override-4');
expect(harness.find('div')).toHaveReactProps({
title: 'count4',
id: 'Override4',
});

// Back to not setting an override, so back to using the incremental id
harness.find('button')!.trigger('onClick');
expect(harness.find(HasProp)!.html()).toStrictEqual('count5 :: polaris-1');
expect(harness.find('div')).toHaveReactProps({
title: 'count5',
id: 'Polaris1',
});
});
});
26 changes: 13 additions & 13 deletions src/utilities/unique-id/tests/unique-id-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@ describe('UniqueIdFactory', () => {
it('returns unique IDs across multiple calls', () => {
const uniqueIdFactory = new UniqueIdFactory(globalIdGeneratorFactory);

expect(uniqueIdFactory.nextId('')).toStrictEqual('polaris-1');
expect(uniqueIdFactory.nextId('')).toStrictEqual('polaris-2');
expect(uniqueIdFactory.nextId('')).toStrictEqual('polaris-3');
expect(uniqueIdFactory.nextId('')).toStrictEqual('Polaris1');
expect(uniqueIdFactory.nextId('')).toStrictEqual('Polaris2');
expect(uniqueIdFactory.nextId('')).toStrictEqual('Polaris3');

expect(uniqueIdFactory.nextId('a')).toStrictEqual('polaris-a1');
expect(uniqueIdFactory.nextId('a')).toStrictEqual('polaris-a2');
expect(uniqueIdFactory.nextId('a')).toStrictEqual('polaris-a3');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('PolarisA1');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('PolarisA2');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('PolarisA3');
});

it('returns unique IDs across prefixes', () => {
const uniqueIdFactory = new UniqueIdFactory(globalIdGeneratorFactory);

expect(uniqueIdFactory.nextId('a')).toStrictEqual('polaris-a1');
expect(uniqueIdFactory.nextId('a')).toStrictEqual('polaris-a2');
expect(uniqueIdFactory.nextId('a')).toStrictEqual('polaris-a3');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('PolarisA1');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('PolarisA2');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('PolarisA3');
});

it('can accept a custom factory', () => {
const customIdGeneratorFactory = (prefix: string) => {
let index = 101;
return () => `custom-${prefix}${index++}`;
return () => `Custom${prefix}${index++}`;
};

const uniqueIdFactory = new UniqueIdFactory(customIdGeneratorFactory);

expect(uniqueIdFactory.nextId('')).toStrictEqual('custom-101');
expect(uniqueIdFactory.nextId('')).toStrictEqual('custom-102');
expect(uniqueIdFactory.nextId('a')).toStrictEqual('custom-a101');
expect(uniqueIdFactory.nextId('')).toStrictEqual('Custom101');
expect(uniqueIdFactory.nextId('')).toStrictEqual('Custom102');
expect(uniqueIdFactory.nextId('A')).toStrictEqual('CustomA101');
});
});
2 changes: 1 addition & 1 deletion src/utilities/unique-id/unique-id-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ export class UniqueIdFactory {

export function globalIdGeneratorFactory(prefix = '') {
let index = 1;
return () => `polaris-${prefix}${index++}`;
return () => `Polaris${prefix}${index++}`;
}

0 comments on commit 7669582

Please sign in to comment.