Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@doodle/components / src / components / controls / Input / __tests__ / MultiEmailSelect / MultiEmailSelect.spec.js
Size: Mime:
import React from 'react';
import { mount } from 'enzyme';
import MultiEmailSelect from '../../MultiEmailSelect/MultiEmailSelect';
import Option from '../../MultiEmailSelect/Option';
import { colorBrand200, colorRed200 } from '../../../../constants/colors';

const CheckIcon = require('../../../../visuals/Icon/svg/d_check.svg');
const QuestionmarkIcon = require('../../../../visuals/Icon/svg/d_questionmark.svg');
const PeopleIcon = require('../../../../visuals/Icon/svg/ic_people.svg');

describe('MultiEmailSelect', () => {
  let placeholder;
  let note;
  let emailsLimit;
  let options;
  let initialValues;
  let component;
  let input;
  let onValueChangeSpy;

  const mockPasteEvent = text => {
    const event = {
      preventDefault: jest.fn(),
      clipboardData: {
        getData: () => text,
      },
    };
    return event;
  };

  beforeAll(() => {
    placeholder = 'Enter emails';
    note = '"Allow entire domains: @example.com, or subdomains: @*.example.com"';
    emailsLimit = 50;
    options = [
      { value: 'tt@doodle.com', label: 'Timo Timber' },
      { value: 'tay@doodle.com', label: 'Tayo Awoyemi' },
      { value: 'st@stan.com', label: 'Stan Theman' },
      { value: 'zh@doodle.com', label: 'Zari fari' },
      { value: 'mms@doodle.com', label: 'Mima Salu' },
      { value: 'kl@doodle.com', label: 'Klaus Larifari' },
      { value: 'opef@doodle.com', label: 'Opaloda Ottoddf' },
      { value: 'opfe@doodle.com', label: 'Opaidap Ottod' },
      { value: 'opaa@doodle.com', label: 'Opalfodks Ottod' },
      { value: 'fran@doodle.example.com', label: 'Fran Example' },
      { value: 'carolina@doodle.example.com', label: 'Carolina Example' },
    ];
    initialValues = [{ value: 'test@email.com', label: 'Test Label' }];
    onValueChangeSpy = jest.fn();
  });

  beforeEach(() => {
    component = mount(
      <MultiEmailSelect
        placeholder={placeholder}
        note={note}
        emailsLimit={emailsLimit}
        options={options}
        onValueChange={onValueChangeSpy}
      />
    );
    input = component.find('input');
  });

  it('matches a snapshot', () => {
    expect(component.getElement()).toMatchSnapshot();
  });

  it('does not display the suggestion menu if there are less then 3 characters', () => {
    input.instance().value = 'ti';
    input.simulate('change');
    expect(component.find('.MultiEmailSelect__menu').length).toBe(0);
  });

  it('displays the suggestion menu if there are 3 or more characters', () => {
    input.instance().value = 'tim';
    input.simulate('change');
    expect(component.find('.MultiEmailSelect__menu').length).toBe(1);
  });

  it('displays the correct option in the suggestion menu if there are 3 or more characters', () => {
    input.instance().value = 'tim';
    input.simulate('change');
    expect(
      component
        .find('.MultiEmailSelect__option-label')
        .at(1)
        .text()
    ).toBe('Timo Timber');
  });

  it('adds a domain to the selected option', () => {
    input.instance().value = 'neu@neu.de';
    input.simulate('change', { target: { value: 'neu@neu.de' } });
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find('.MultiEmailSelect__multi-value__label').text()).toBe('neu@neu.de');
  });

  it('adds a domain to the selected option', () => {
    input.instance().value = 'a@test.de';
    input.simulate('change', { target: { value: 'a@test.de' } });
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find('.MultiEmailSelect__multi-value__label').text()).toBe('a@test.de');
  });

  it('does not add a new email adress to the selected option if it has multiple @s', () => {
    input.instance().value = 'test@test@test.de';
    input.simulate('change', { target: { value: 'test@test@test.de' } });
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find('.MultiEmailSelect__multi-value__label').exists()).toBe(true);
  });

  it('does add inputs that are neither emails, domains or options', () => {
    input.instance().value = 'testestest';
    input.simulate('change', { target: { value: 'testestest' } });
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find('.MultiEmailSelect__multi-value__label').exists()).toBeTruthy();
  });

  it('adds a entry from the options to the selected options if the name of that option is entered', () => {
    input.instance().value = 'Timo Timber';
    input.simulate('change', { target: { value: 'Timo' } });
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find('.MultiEmailSelect__multi-value__label').text()).toBe('Timo Timber');
  });

  it('adds pasted email to the selected options', () => {
    component.instance().onPasteHandler(mockPasteEvent('test@test.de'));
    component.update();
    expect(component.find('.MultiEmailSelect__multi-value__label').text()).toBe('test@test.de');
  });

  it('adds multiple space sperated, pasted emails to the selected options', () => {
    component.instance().onPasteHandler(mockPasteEvent('test@test.de hallo@hallo.de 123@123.de'));
    component.update();
    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(3);
  });

  it('adds multiple comma sperated, pasted emails to the selected options', () => {
    component.instance().onPasteHandler(mockPasteEvent('test@test.de, hallo@hallo.de, 123@123.de'));
    component.update();
    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(3);
  });

  it('adds multiple semicolon sperated, pasted emails to the selected options', () => {
    component.instance().onPasteHandler(mockPasteEvent('test@test.de; hallo@hallo.de; 123@123.de'));
    component.update();
    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(3);
  });

  it('adds pasted emails from complex strings to the selected options', () => {
    [
      'Patricia Magro (pm@doodle.com), Katharina Schneider (ks@doodle.com)',
      '„Patricia Magro“ (pm@doodle.com), „Katharina Schneider“ (ks@doodle.com)',
      '"Patricia Magro" (pm@doodle.com), "Katharina Schneider" (ks@doodle.com)',
      '‚Patricia Magro’ (pm@doodle.com), ‚Katharina Schneider’ (ks@doodle.com)',
      "'Patricia Magro' (pm@doodle.com), 'Katharina Schneider' (ks@doodle.com)",
      'Patricia Magro (pm@doodle.com)\nKatharina Schneider (ks@doodle.com)',
      'pm@doodle.com\nks@doodle.com',
      'Patricia Magro <pm@doodle.com>, Katharina Schneider <ks@doodle.com>',
    ].forEach(testCase => {
      component.instance().onPasteHandler(mockPasteEvent(testCase));
      component.update();
      expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(2);
      // remove the selected options
      input.simulate('keyDown', { keyCode: 8, key: 'Backspace' });
      input.simulate('keyDown', { keyCode: 8, key: 'Backspace' });
    });
  });

  it('should add all pasted invalid emails', () => {
    component.instance().onPasteHandler(mockPasteEvent('test@test.de hallo@hallo@hallo.de 123 hey@ @okay.de'));
    component.update();
    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(5);
  });

  it('should not add emails when the limit is reached', () => {
    component.setProps({ emailsLimit: 3 });
    component.instance().onPasteHandler(mockPasteEvent('test@test.de hallo@hallo.de 123@123.de'));
    component.update();

    input.instance().value = 'new@new.de';
    input.simulate('change', { target: { value: 'new@new.de' } });
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });

    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(3);
  });

  it('should not add emails via paste when the limit is reached', () => {
    component.setProps({ emailsLimit: 3 });
    component.instance().onPasteHandler(mockPasteEvent('test@test.de hallo@hallo.de 123@123.de'));
    component.update();

    component.instance().onPasteHandler(mockPasteEvent('new@new.de doodle@doodle.de'));
    component.update();

    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(3);
  });

  it('should add all emails via paste, even when the limit is reached, while pasting the emails', () => {
    component.setProps({ emailsLimit: 3 });
    component
      .instance()
      .onPasteHandler(mockPasteEvent('test@test.de hallo@hallo.de 123@123.de new@new.de doodle@doodle.de'));
    component.update();

    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(5);
  });

  it('should show the email suggestion hook if there are no options provided and the input field got valid value', () => {
    component.setProps({
      options: null,
      activateSuggestions: {
        headline: 'See contacts suggestions',
        text: 'From Gmail, Outlook, Office 365',
        buttonText: 'Activate suggestions',
        buttonLink: '/account',
        silentButtonText: 'Later',
      },
    });
    component.instance();
    input.instance().value = 'email@mm.co';
    input.simulate('change', { target: { value: 'email@mm.co' } });
    expect(component.find('.ActivateSuggestions').exists()).toBeTruthy();
  });

  it('should show the initial options in the menu if thesy are provided and the input field is focused', () => {
    component.setProps({
      initialOptions: {
        participated: {
          label: 'Participated',
          icon: CheckIcon,
          options: [{ value: 'aa@doodle.com', label: 'aa@doodle.com' }],
        },
        notParticipated: {
          label: 'Not Participated yet',
          icon: QuestionmarkIcon,
          options: [{ value: 'gg@doodle.com', label: 'gg@doodle.com' }],
        },
        everyone: {
          label: 'Everyone',
          icon: PeopleIcon,
          options: [
            { value: 'aa@doodle.com', label: 'aa@doodle.com' },
            { value: 'gg@doodle.com', label: 'gg@doodle.com' },
          ],
        },
      },
    });
    component.instance();
    input.instance();
    input.simulate('focus');
    expect(component.find(Option).length).toBe(3);
  });

  it('should add the emails from a initial options group', () => {
    component.setProps({
      initialOptions: {
        participated: {
          label: 'Participated',
          icon: CheckIcon,
          options: [{ value: 'aa@doodle.com', label: 'aa@doodle.com' }, { value: 'bb@doodle.com', label: 'Bella Be' }],
        },
        notParticipated: {
          label: 'Not Participated yet',
          icon: QuestionmarkIcon,
          options: [{ value: 'gg@doodle.com', label: 'gg@doodle.com' }],
        },
        everyone: {
          label: 'Everyone',
          icon: PeopleIcon,
          options: [
            { value: 'aa@doodle.com', label: 'aa@doodle.com' },
            { value: 'gg@doodle.com', label: 'gg@doodle.com' },
          ],
        },
      },
    });
    component.instance();
    input.instance();
    input.simulate('focus');
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find('.MultiEmailSelect__multi-value__label').length).toBe(2);
  });

  it('should remove an initial options group from the suggestion menu after it has been selected', () => {
    component.setProps({
      initialOptions: {
        participated: {
          label: 'Participated',
          icon: CheckIcon,
          options: [{ value: 'aa@doodle.com', label: 'aa@doodle.com' }, { value: 'bb@doodle.com', label: 'Bella Be' }],
        },
        notParticipated: {
          label: 'Not Participated yet',
          icon: QuestionmarkIcon,
          options: [{ value: 'gg@doodle.com', label: 'gg@doodle.com' }],
        },
        everyone: {
          label: 'Everyone',
          icon: PeopleIcon,
          options: [
            { value: 'aa@doodle.com', label: 'aa@doodle.com' },
            { value: 'gg@doodle.com', label: 'gg@doodle.com' },
          ],
        },
      },
    });
    component.instance();
    input.instance();
    input.simulate('focus');
    input.simulate('keyDown', { keyCode: 9, key: 'Tab' });
    expect(component.find(Option).length).toBe(2);
  });

  it('should render provided initial values', () => {
    component.setState({ value: initialValues });
    expect(component.find('.MultiEmailSelect__multi-value__label').text()).toBe('Test Label');
  });

  it('should display the values with a custom color, when a decorator is provided', () => {
    component.setProps({
      decorateValue: valueEntry =>
        valueEntry.value === 'test@email.com' ? { style: { backgroundColor: '#ababab' } } : null,
    });
    component.setState({
      value: initialValues,
    });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe('#ababab');
  });

  it('should display the values with the default color, when the decorator does not return anything', () => {
    component.setProps({
      decorateValue: valueEntry =>
        valueEntry.value === 'another@email.com' ? { style: { backgroundColor: '#ababab' } } : null,
    });
    component.setState({
      value: initialValues,
    });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe(
      colorBrand200
    );
  });

  it('should display invalid values with the error colour', () => {
    const value = [{ value: 'invalid', label: 'Test' }];
    component.setState({ value });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe(colorRed200);
  });

  it('exposes values including a property that indicates whether the value is valid or not', () => {
    component.instance().onChangeHandler([{ value: 'invalid*invitee', label: 'invalid*invitee' }]);
    expect(onValueChangeSpy).toHaveBeenLastCalledWith([
      {
        label: 'invalid*invitee',
        value: 'invalid*invitee',
        valid: false,
      },
    ]);
  });

  it('displays name as label if value exists in contact list', () => {
    const value = [{ value: 'bb@doodle.com', label: 'Bella Be' }];
    component.setState({ value });
    expect(component.find('.MultiEmailSelect__multi-value__label').text()).toBe('Bella Be');
  });

  it('button should be in disabled state if 1 or more invalid values', () => {
    const values = [{ value: 'invalid', label: 'invalid' }, { value: 'aa@doodle.com', label: 'aa@doodle.com' }];
    component.setState({ value: values });
    expect(component.find('.Button').prop('disabled')).toBe(true);
  });

  it('button should be in disabled state if email limit has been exceeded', () => {
    const values = [
      { value: 'aa@doodle.com', label: 'aa@doodle.com' },
      { value: 'gg@doodle.com', label: 'gg@doodle.com' },
      { value: 'bb@doodle.com', label: 'Bella Be' },
    ];
    component.setProps({ emailsLimit: 2 });
    component.setState({ value: values });
    expect(component.find('.Button').prop('disabled')).toBe(true);
  });

  it('should consider emails with an incomplete domain invalid', () => {
    const value = [{ value: 'e@e', label: 'Test' }];
    component.setState({ value });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe(colorRed200);
  });

  it('should consider two emails that are not separated by a space as invalid', () => {
    const value = [{ value: 'hello@hello.comhi@hi.co', label: 'Test' }];
    component.setState({ value });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe(colorRed200);
  });

  it('should not accept special characters in the domain', () => {
    const value = [{ value: 'hey@ex$mple.com', label: 'Test' }];
    component.setState({ value });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe(colorRed200);
  });

  it('should consider emails without a name before the domain (or subdomain) as invalid', () => {
    const value = [{ value: '@example.com', label: 'Test' }];
    component.setState({ value });
    expect(component.find('.MultiEmailSelect__multi-value-container').prop('style').backgroundColor).toBe(colorRed200);
  });

  it('allows text to stay inside the component when "blur" is triggered', () => {
    input.instance().value = 'neu@neu.de';
    input.simulate('change', { target: { value: 'neu@neu.de' } });
    input.simulate('blur');
    expect(component.exists('.MultiEmailSelect__value-container input')).toBe(true);
    expect(component.exists('.MultiEmailSelect__multi-value-container')).toBe(false);
  });

  it('adds a new invitee and cleans the input when an email is confirmed', () => {
    input.instance().value = 'neu@neu.de';
    input.simulate('change', { target: { value: 'neu@neu.de' } });
    input.simulate('keyDown', { keyCode: 13, key: 'Enter' });
    expect(component.exists('.MultiEmailSelect__multi-value-container')).toBe(true);
    expect(component.find('.MultiEmailSelect__value-container input').text()).toBe('');
  });
});