@testing-library/dom#fireEvent JavaScript Examples

The following examples show how to use @testing-library/dom#fireEvent. 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: ProfileDOMTestingLib.test.js    From Simplify-Testing-with-React-Testing-Library with MIT License 6 votes vote down vote up
test('Profile, given click "hide details" button, shows "display details" button', () => {
  const div = document.createElement('div');
  ReactDOM.render(
    <Profile
      name='John Doe'
      title='Team Lead'
      details='This is my 5th year and I love helping others'
    />,
    div
  );
  document.body.appendChild(div);
  const hideDetailsBtn = screen.getByRole('button', { name: /hide details/i });

  fireEvent.click(hideDetailsBtn);
  const displayDetailsBtn = screen.getByRole('button', {
    name: /display details/i,
  });

  expect(displayDetailsBtn.textContent).toEqual('Display Details');

  const removedHideDetailsBtn = screen.queryByRole('button', {
    name: /hide details/i,
  });
  expect(removedHideDetailsBtn).not.toBeInTheDocument();

  // Test cleanup
  div.remove();
});
Example #2
Source File: LibraryAccessForm.spec.jsx    From frontend-app-library-authoring with GNU Affero General Public License v3.0 6 votes vote down vote up
testSuite('<LibraryAccessForm />', () => {
  it('Renders an error for the email field', async () => {
    const library = libraryFactory();
    const props = { library, errorFields: { email: 'Too difficult to remember.' }, ...commonMocks() };
    const { container } = await ctxRender(<LibraryAccessFormContainer {...props} />);
    expect(getByText(container, /Too difficult/)).toBeTruthy();
  });
  it('Submits and adds a new user.', async () => {
    const library = libraryFactory();
    const props = { library, ...commonMocks() };
    const { addUser } = props;
    const user = userFactory();
    addUser.mockImplementation(() => immediate(user));
    const { container } = await ctxRender(<LibraryAccessFormContainer {...props} />);
    const emailField = getByLabelText(container, 'Email');
    fireEvent.change(emailField, { target: { value: '[email protected]' } });
    const submitButton = getByRole(container, 'button', { name: /Submit/ });
    fireEvent.click(submitButton);
    await waitFor(() => expect(addUser).toHaveBeenCalledWith({
      libraryId: library.id, data: { email: '[email protected]', access_level: LIBRARY_ACCESS.READ },
    }));
    expect(emailField.value).toBe('');
  });
  it('Closes out', async () => {
    const library = libraryFactory();
    const props = { library, ...commonMocks() };
    const { setShowAdd } = props;
    const { container } = await ctxRender(
      <LibraryAccessFormContainer
        {...props}
      />,
    );
    const button = getByRole(container, 'button', { name: /Cancel/ });
    fireEvent.click(button);
    expect(setShowAdd).toHaveBeenCalledWith(false);
  });
});
Example #3
Source File: shared.js    From emoji-picker-element with Apache License 2.0 6 votes vote down vote up
export async function openSkintoneListbox (container) {
  await waitFor(() => expect(getByRole(container, 'button', { name: /Choose a skin tone/ }))
    .toBeVisible())
  expect(queryAllByRole(container, 'listbox', { name: 'Skin tones' })).toHaveLength(0)
  await fireEvent.click(getByRole(container, 'button', { name: /Choose a skin tone/ }))
  await waitFor(() => expect(getByRole(container, 'listbox', { name: 'Skin tones' })).toBeVisible())
  expect(getAllByRole(container, 'option')).toHaveLength(6)
  getByRole(container, 'option', { name: 'Default', selected: true }).focus()
  await waitFor(() => expect(getByRole(container, 'option', { name: 'Default', selected: true }))
    .toBeVisible())
  // JSDom doesn't fire transitionend events, so we do it manually here
  // https://github.com/jsdom/jsdom/issues/1781#issuecomment-467935000
  fireEvent(getByRole(container, 'listbox', { name: 'Skin tones' }), new Event('transitionend'))
}
Example #4
Source File: unit.spec.js    From js-test-basic with MIT License 6 votes vote down vote up
it('- 버튼 클릭시 counter의 dec()를 호출한 후 다시 렌더링한다.', () => {
  let value = 10;
  const counterDec = jest.fn().mockImplementation(() => {
    value = 9;
  });
  createCounter.mockImplementation(() => ({
    val: () => value,
    isMin: () => false,
    isMax: () => false,
    dec: counterDec
  }));

  createUICounter(container);

  fireEvent.click(getByText(container, '-'));
  expect(counterDec).toHaveBeenCalled();
  expect(getByText(container, '9')).toBeVisible();
});
Example #5
Source File: unit.spec.js    From js-test-basic with MIT License 6 votes vote down vote up
it('+ 버튼 클릭시 counter의 inc()를 호출한 후 다시 렌더링한다.', () => {
  let value = 10;
  const counterInc = jest.fn().mockImplementation(() => {
    value = 11;
  });
  createCounter.mockImplementation(() => ({
    val: () => value,
    isMin: () => false,
    isMax: () => false,
    inc: counterInc
  }));

  createUICounter(container);

  fireEvent.click(getByText(container, '+'));
  expect(counterInc).toHaveBeenCalled();
  expect(getByText(container, '11')).toBeVisible();
});
Example #6
Source File: index.js    From Path-Finding-Visualizer with MIT License 6 votes vote down vote up
function clickLabel(label) {
  fireEvent.mouseOver(label);
  fireEvent.mouseMove(label);
  fireEvent.mouseDown(label);
  fireEvent.mouseUp(label);

  if (label.htmlFor) {
    const input = document.getElementById(label.htmlFor);
    input.focus();
    fireEvent.click(label);
  } else {
    const input = label.querySelector("input,textarea,select");
    input.focus();
    label.focus();
    fireEvent.click(label);
  }
}
Example #7
Source File: Login.test.js    From Simplify-Testing-with-React-Testing-Library with MIT License 6 votes vote down vote up
test('Login, given credentials, returns enabled submit button', () => {
  const div = document.createElement('div');
  ReactDOM.render(<Login />, div);
  document.body.appendChild(div);
  const username = screen.getByRole('textbox', { name: /username/i });
  const password = screen.getByLabelText(/password/i);
  const rememberMe = screen.getByRole('checkbox');
  const loginBtn = screen.getByRole('button', { name: /login/i });

  const fakeUser = {
    username: 'test user',
    password: '123password',
  };
  fireEvent.change(username, { target: { value: fakeUser.username } });
  fireEvent.change(password, { target: { value: fakeUser.password } });
  fireEvent.click(rememberMe);

  expect(screen.getByTestId('form')).toHaveFormValues({
    username: fakeUser.username,
    password: fakeUser.password,
    rememberMe: true,
  });

  expect(loginBtn).not.toBeDisabled();

  // Test cleanup
  div.remove();
});
Example #8
Source File: index.js    From Path-Finding-Visualizer with MIT License 6 votes vote down vote up
function selectOption(select, option) {
  fireEvent.mouseOver(option);
  fireEvent.mouseMove(option);
  fireEvent.mouseDown(option);
  fireEvent.focus(option);
  fireEvent.mouseUp(option);
  fireEvent.click(option);

  option.selected = true;

  fireEvent.change(select);
}
Example #9
Source File: index.js    From Path-Finding-Visualizer with MIT License 6 votes vote down vote up
function dblClickCheckbox(checkbox) {
  fireEvent.mouseOver(checkbox);
  fireEvent.mouseMove(checkbox);
  fireEvent.mouseDown(checkbox);
  fireEvent.mouseUp(checkbox);
  fireEvent.click(checkbox);
  fireEvent.mouseDown(checkbox);
  fireEvent.mouseUp(checkbox);
  fireEvent.click(checkbox);
}
Example #10
Source File: index.js    From Path-Finding-Visualizer with MIT License 6 votes vote down vote up
function dblClickElement(element) {
  fireEvent.mouseOver(element);
  fireEvent.mouseMove(element);
  fireEvent.mouseDown(element);
  element.focus();
  fireEvent.mouseUp(element);
  fireEvent.click(element);
  fireEvent.mouseDown(element);
  fireEvent.mouseUp(element);
  fireEvent.click(element);
  fireEvent.dblClick(element);

  const labelAncestor = findTagInParents(element, "LABEL");
  labelAncestor && clickLabel(labelAncestor);
}
Example #11
Source File: index.js    From Path-Finding-Visualizer with MIT License 6 votes vote down vote up
function clickElement(element) {
  fireEvent.mouseOver(element);
  fireEvent.mouseMove(element);
  fireEvent.mouseDown(element);
  element.focus();
  fireEvent.mouseUp(element);
  fireEvent.click(element);

  const labelAncestor = findTagInParents(element, "LABEL");
  labelAncestor && clickLabel(labelAncestor);
}
Example #12
Source File: index.js    From Path-Finding-Visualizer with MIT License 6 votes vote down vote up
function clickBooleanElement(element) {
  if (element.disabled) return;

  fireEvent.mouseOver(element);
  fireEvent.mouseMove(element);
  fireEvent.mouseDown(element);
  fireEvent.mouseUp(element);
  fireEvent.click(element);
}
Example #13
Source File: index.js    From Path-Finding-Visualizer with MIT License 5 votes vote down vote up
function fireChangeEvent(event) {
  fireEvent.change(event.target);
  event.target.removeEventListener("blur", fireChangeEvent);
}
Example #14
Source File: dataSource.test.js    From emoji-picker-element with Apache License 2.0 5 votes vote down vote up
describe('dataSource test', () => {
  beforeEach(basicBeforeEach)
  afterEach(basicAfterEach)

  test('emoji with no shortcodes still work', async () => {
    mockDataSourceWithNoShortcodes()
    const dataSource = NO_SHORTCODES
    const picker = new Picker({ dataSource, locale: 'en-no-shortcodes' })
    document.body.appendChild(picker)
    const container = picker.shadowRoot.querySelector('.picker')
    await tick(20)

    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /?/ })).toBeVisible())

    // no shortcodes, no title
    expect(getByRole(container, 'menuitem', { name: /?/ }).getAttribute('title')).toStrictEqual('')
    expect(getByRole(container, 'menuitem', { name: /?/ }).getAttribute('aria-label')).toStrictEqual('?')

    await picker.database.delete()
    await tick(20)
    document.body.removeChild(picker)
    await tick(20)
  })

  test('emoji with emojibase v5 data source still work', async () => {
    mockEmojibaseV5DataSource()
    const dataSource = EMOJIBASE_V5
    const picker = new Picker({ dataSource, locale: 'en-emojibase' })
    document.body.appendChild(picker)
    const container = picker.shadowRoot.querySelector('.picker')
    await tick(20)

    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /?/ })).toBeVisible())

    // no shortcodes, no title
    expect(getByRole(container, 'menuitem', { name: /?/ }).getAttribute('title')).toStrictEqual('gleeful')
    expect(getByRole(container, 'menuitem', { name: /?/ }).getAttribute('aria-label')).toStrictEqual('?, gleeful')

    await picker.database.delete()
    await tick(20)
    document.body.removeChild(picker)
    await tick(20)
  })

  test('emoji with array skin tones work', async () => {
    mockDataSourceWithArraySkinTones()

    const dataSource = WITH_ARRAY_SKIN_TONES
    const picker = new Picker({ dataSource, locale: 'en-arrayskintones' })
    document.body.appendChild(picker)
    const container = picker.shadowRoot.querySelector('.picker')
    await tick(20)

    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /?/ })).toBeVisible())
    await fireEvent.click(getByRole(container, 'tab', { name: /People and body/ }))
    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /?‍?‍?/ })).toBeVisible())

    await openSkintoneListbox(container)

    await fireEvent.click(getByRole(container, 'option', { name: /Medium-Dark/ }))

    // both people in the emoji should have the same skin tone
    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /??‍?‍??/ })).toBeVisible())

    await picker.database.delete()
    await tick(20)
    document.body.removeChild(picker)
    await tick(20)
  })
})
Example #15
Source File: noResizeObserver.test.js    From emoji-picker-element with Apache License 2.0 5 votes vote down vote up
// TODO: we can remove these tests when/if we stop supporting browsers without ResizeObserver
// https://caniuse.com/resizeobserver

describe('ResizeObserver unsupported', () => {
  let picker
  let container
  let oldResizeObserver

  beforeEach(async () => {
    basicBeforeEach()

    oldResizeObserver = global.ResizeObserver
    delete global.ResizeObserver
    resetResizeObserverSupported()

    picker = new Picker({ dataSource: ALL_EMOJI })
    document.body.appendChild(picker)
    container = picker.shadowRoot.querySelector('.picker')
    await tick(40)
  })

  afterEach(async () => {
    await tick(40)
    document.body.removeChild(picker)
    await tick(40)
    await new Database({ dataSource: ALL_EMOJI }).delete()
    await tick(40)
    await basicAfterEach()

    global.ResizeObserver = oldResizeObserver
    resetResizeObserverSupported()
  })

  test('basic picker test', async () => {
    const numInGroup1 = truncatedEmoji.filter(_ => _.group === 0).length
    const numInGroup2 = truncatedEmoji.filter(_ => _.group === 1).length

    await waitFor(() => expect(getByRole(container, 'button', { name: 'Choose a skin tone (currently Default)' })).toBeVisible())
    expect(getAllByRole(container, 'tab')).toHaveLength(groups.length)

    expect(getByRole(container, 'tab', { name: 'Smileys and emoticons', selected: true })).toBeVisible()
    await waitFor(() => expect(
      testingLibrary.getAllByRole(getByRole(container, 'tabpanel'), 'menuitem')).toHaveLength(numInGroup1)
    )

    expect(getByRole(container, 'tab', { name: 'People and body' })).toBeVisible()
    fireEvent.click(getByRole(container, 'tab', { name: 'People and body' }))

    await waitFor(() => expect(
      testingLibrary.getAllByRole(getByRole(container, 'tabpanel'), 'menuitem')).toHaveLength(numInGroup2))

    expect(getByRole(container, 'tab', { name: 'People and body', selected: true })).toBeVisible()
  })
})
Example #16
Source File: index.js    From Path-Finding-Visualizer with MIT License 4 votes vote down vote up
userEvent = {
  click(element) {
    const focusedElement = element.ownerDocument.activeElement;
    const wasAnotherElementFocused =
      focusedElement !== element.ownerDocument.body &&
      focusedElement !== element;
    if (wasAnotherElementFocused) {
      fireEvent.mouseMove(focusedElement);
      fireEvent.mouseLeave(focusedElement);
    }

    switch (element.tagName) {
      case "LABEL":
        clickLabel(element);
        break;
      case "INPUT":
        if (element.type === "checkbox" || element.type === "radio") {
          clickBooleanElement(element);
          break;
        }
      default:
        clickElement(element);
    }

    wasAnotherElementFocused && focusedElement.blur();
  },

  dblClick(element) {
    const focusedElement = document.activeElement;
    const wasAnotherElementFocused =
      focusedElement !== document.body && focusedElement !== element;
    if (wasAnotherElementFocused) {
      fireEvent.mouseMove(focusedElement);
      fireEvent.mouseLeave(focusedElement);
    }

    switch (element.tagName) {
      case "INPUT":
        if (element.type === "checkbox") {
          dblClickCheckbox(element);
          break;
        }
      default:
        dblClickElement(element);
    }

    wasAnotherElementFocused && focusedElement.blur();
  },

  selectOptions(element, values) {
    const focusedElement = document.activeElement;
    const wasAnotherElementFocused =
      focusedElement !== document.body && focusedElement !== element;
    if (wasAnotherElementFocused) {
      fireEvent.mouseMove(focusedElement);
      fireEvent.mouseLeave(focusedElement);
    }

    clickElement(element);

    const valArray = Array.isArray(values) ? values : [values];
    const selectedOptions = Array.from(element.children).filter(
      opt => opt.tagName === "OPTION" && valArray.includes(opt.value)
    );

    if (selectedOptions.length > 0) {
      if (element.multiple) {
        selectedOptions.forEach(option => selectOption(element, option));
      } else {
        selectOption(element, selectedOptions[0]);
      }
    }

    wasAnotherElementFocused && focusedElement.blur();
  },

  async type(element, text, userOpts = {}) {
    if (element.disabled) return;
    const defaultOpts = {
      allAtOnce: false,
      delay: 0
    };
    const opts = Object.assign(defaultOpts, userOpts);
    if (opts.allAtOnce) {
      if (element.readOnly) return;
      fireEvent.input(element, { target: { value: text } });
    } else {
      let actuallyTyped = "";
      for (let index = 0; index < text.length; index++) {
        const char = text[index];
        const key = char; // TODO: check if this also valid for characters with diacritic markers e.g. úé etc
        const keyCode = char.charCodeAt(0);

        if (opts.delay > 0) await wait(opts.delay);

        const downEvent = fireEvent.keyDown(element, {
          key: key,
          keyCode: keyCode,
          which: keyCode
        });
        if (downEvent) {
          const pressEvent = fireEvent.keyPress(element, {
            key: key,
            keyCode,
            charCode: keyCode
          });
          if (pressEvent) {
            actuallyTyped += key;
            if (!element.readOnly)
              fireEvent.input(element, {
                target: {
                  value: actuallyTyped
                },
                bubbles: true,
                cancelable: true
              });
          }
        }

        fireEvent.keyUp(element, {
          key: key,
          keyCode: keyCode,
          which: keyCode
        });
      }
    }
    element.addEventListener("blur", fireChangeEvent);
  },

  tab({ shift = false, focusTrap = document } = {}) {
    const focusableElements = focusTrap.querySelectorAll(
      "input, button, select, textarea, a[href], [tabindex]"
    );
    const list = Array.prototype.filter
      .call(focusableElements, function(item) {
        return item.getAttribute("tabindex") !== "-1";
      })
      .sort((a, b) => {
        const tabIndexA = a.getAttribute("tabindex");
        const tabIndexB = b.getAttribute("tabindex");
        return tabIndexA < tabIndexB ? -1 : tabIndexA > tabIndexB ? 1 : 0;
      });
    const index = list.indexOf(document.activeElement);

    let nextIndex = shift ? index - 1 : index + 1;
    let defaultIndex = shift ? list.length - 1 : 0;

    const next = list[nextIndex] || list[defaultIndex];

    if (next.getAttribute("tabindex") === null) {
      next.setAttribute("tabindex", "0"); // jsdom requires tabIndex=0 for an item to become 'document.activeElement' (the browser does not)
      next.focus();
      next.removeAttribute("tabindex"); // leave no trace. :)
    } else {
      next.focus();
    }
  }
}
Example #17
Source File: ProjectDetails.test.jsx    From ui with MIT License 4 votes vote down vote up
describe('ProjectDetails', () => {
  let metadataCreated;
  beforeEach(() => {
    jest.clearAllMocks();
    metadataCreated = jest.spyOn(createMetadataTrack, 'default');
  });

  it('Has a title, project ID and description', () => {
    render(
      <Provider store={mockStore(noDataState)}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );

    // Project name
    expect(screen.getByText(experimentName)).toBeDefined();

    // Project uuid
    expect(screen.queryByText(experiment1id)).toBeDefined();

    // Description
    expect(screen.queryByText(experimentDescription)).toBeDefined();
  });

  it('Has 4 buttons', () => {
    render(
      <Provider store={mockStore(noDataState)}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );

    expect(screen.getByText('Add samples')).toBeDefined();
    expect(screen.getByText('Add metadata')).toBeDefined();
    expect(screen.getByText('Download')).toBeDefined();
    expect(screen.getByText('Process project')).toBeDefined();
  });

  it('Add metadata button is disabled if there is no data', () => {
    render(
      <Provider store={mockStore(noDataState)}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );

    const metadataButton = screen.getByText('Add metadata').closest('button');

    expect(metadataButton).toBeDisabled();
  });

  it('Add metadata button is enabled if there is data', () => {
    render(
      <Provider store={mockStore(withDataState)}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );

    const metadataButton = screen.getByText('Add metadata').closest('button');

    expect(metadataButton).not.toBeDisabled();
  });

  it('Download dropdown is disabled if there are no samples', () => {
    const store = createStore(rootReducer, _.cloneDeep(noDataState), applyMiddleware(thunk));
    render(
      <Provider store={store}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );
    const downloadDropdown = screen.getByText('Download').closest('button');
    expect(downloadDropdown).toBeDisabled();
  });

  it('Shows all the samples that are uploaded', () => {
    render(
      <Provider store={mockStore(withDataState)}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );

    expect(screen.getByText(sample1Name)).toBeDefined();
    expect(screen.getByText(sample2Name)).toBeDefined();
  });

  it('Creates a metadata column', async () => {
    const store = createStore(rootReducer, _.cloneDeep(withDataState), applyMiddleware(thunk));
    await act(async () => {
      render(
        <Provider store={store}>
          <ProjectDetails width={width} height={height} />
        </Provider>,
      );
    });

    const addMetadata = screen.getByText('Add metadata');
    userEvent.click(addMetadata);
    const field = screen.getByRole('textbox');
    userEvent.type(field, 'myBrandNewMetadata');
    fireEvent.keyDown(field, { key: 'Enter', code: 'Enter' });
    await waitFor(() => expect(metadataCreated).toBeCalledTimes(1));
  });

  it('Cancels metadata creation', () => {
    const store = createStore(rootReducer, _.cloneDeep(withDataState), applyMiddleware(thunk));
    render(
      <Provider store={store}>
        <ProjectDetails width={width} height={height} />
      </Provider>,
    );
    const addMetadata = screen.getByText('Add metadata');
    userEvent.click(addMetadata);
    const field = screen.getByRole('textbox');
    userEvent.type(field, 'somenewMeta');
    fireEvent.keyDown(field, { key: 'Escape', code: 'Escape' });

    expect(store.getState().experiments[experiment1id].metadataKeys).toEqual(['metadata-1']);
  });
});
Example #18
Source File: favorites.test.js    From emoji-picker-element with Apache License 2.0 4 votes vote down vote up
describe('Favorites UI', () => {
  let picker
  let container

  beforeEach(async () => {
    basicBeforeEach()

    const dataWithFavorites = uniqBy([
      ...truncatedEmoji,
      ...allData.filter(_ => MOST_COMMONLY_USED_EMOJI.includes(_.emoji))
    ], _ => _.emoji)

    fetch.get(dataSource, () => new Response(JSON.stringify(dataWithFavorites), { headers: { ETag: 'W/favs' } }))
    fetch.head(dataSource, () => new Response(null, { headers: { ETag: 'W/favs' } }))

    picker = new Picker({ dataSource, locale: 'en' })
    document.body.appendChild(picker)
    container = picker.shadowRoot.querySelector('.picker')

    await tick(40)
  })
  afterEach(async () => {
    await tick(40)
    document.body.removeChild(picker)
    await tick(40)
    await basicAfterEach()
  })

  async function remount () {
    await tick(40)
    document.body.removeChild(picker)
    await tick(40)
    document.body.appendChild(picker)
    container = picker.shadowRoot
    await tick(40)
  }

  test('Favorites UI basic test', async () => {
    let favoritesBar = getByRole(container, 'menu', { name: 'Favorites' })
    expect(favoritesBar).toBeVisible()
    await waitFor(() => expect(getAllByRole(favoritesBar, 'menuitem')).toHaveLength(8))
    expect(getAllByRole(favoritesBar, 'menuitem').map(_ => _.getAttribute('id').substring(4))).toStrictEqual(
      MOST_COMMONLY_USED_EMOJI.slice(0, 8)
    )
    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /?/ })).toBeVisible())
    fireEvent.click(getByRole(container, 'menuitem', { name: /?/ }))

    // have to unmount/remount to force a favorites refresh
    await remount()

    favoritesBar = getByRole(container, 'menu', { name: 'Favorites' })
    await waitFor(() => expect(getAllByRole(favoritesBar, 'menuitem')
      .map(_ => _.getAttribute('id').substring(4))).toStrictEqual([
      '?',
      ...MOST_COMMONLY_USED_EMOJI.slice(0, 7)
    ]
    ))
  })

  test('Favorites with custom emoji', async () => {
    const transparent = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
    const black = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='

    const customEmoji = [
      {
        name: 'transparent',
        shortcodes: ['transparent'],
        url: transparent
      },
      {
        name: 'black',
        shortcodes: ['black'],
        url: black
      }
    ]

    await waitFor(() => expect(getAllByRole(container, 'tab')).toHaveLength(groups.length))

    // when setting custom emoji, they can appear in the favorites
    await tick(40)
    picker.customEmoji = customEmoji
    await tick(40)

    await waitFor(() => expect(getAllByRole(container, 'tab')).toHaveLength(groups.length + 1))

    expect(getByRole(container, 'tab', { name: 'Custom', selected: true })).toBeVisible()
    await tick(40)
    await waitFor(() => expect(queryAllByRole(container, 'menuitem', { name: /transparent/i })).toHaveLength(1), {
      timeout: 5000
    })
    await waitFor(() => expect(getByRole(container, 'menuitem', { name: /transparent/i })).toBeVisible(), {
      timeout: 3000
    })

    fireEvent.click(getByRole(container, 'menuitem', { name: /transparent/i }))
    fireEvent.click(getByRole(container, 'menuitem', { name: /black/i }))

    // have to unmount/remount to force a favorites refresh
    await remount()

    await waitFor(
      () => expect(getByRole(getByRole(container, 'menu', { name: 'Favorites' }), 'menuitem', { name: /transparent/i })).toBeVisible
    )

    await waitFor(
      () => expect(getByRole(getByRole(container, 'menu', { name: 'Favorites' }), 'menuitem', { name: /black/i })).toBeVisible
    )

    // when setting custom emoji back to [], the favorites bar removes the custom emoji
    picker.customEmoji = []

    await waitFor(() => expect(getAllByRole(container, 'tab')).toHaveLength(groups.length))

    await waitFor(
      () => expect(queryAllByRole(getByRole(container, 'menu', { name: 'Favorites' }), 'menuitem', { name: /transparent/i })).toHaveLength(0)
    )
    await waitFor(
      () => expect(queryAllByRole(getByRole(container, 'menu', { name: 'Favorites' }), 'menuitem', { name: /black/i })).toHaveLength(0)
    )
  })
})
Example #19
Source File: LibraryAuthoringPage.spec.jsx    From frontend-app-library-authoring with GNU Affero General Public License v3.0 4 votes vote down vote up
testSuite('<LibraryAuthoringPageContainer />', () => {
  it('Fetches a library when missing', async () => {
    await ctxRender(
      <LibraryAuthoringPageContainer
        match={{ params: { libraryId: 'testtest' } }}
      />,
    );
    await waitFor(() => expect(clearLibrary.fn).toHaveBeenCalled());
    clearLibrary.calls[0].resolve();
    await waitFor(() => expect(fetchLibraryDetail.fn).toHaveBeenCalledWith({ libraryId: 'testtest' }));
  });

  it('Fetches a library when the current library does not match', async () => {
    await ctxRender(
      <LibraryAuthoringPageContainer
        match={{ params: { libraryId: 'testtest' } }}
      />,
      genState(libraryFactory()),
    );
    await waitFor(() => expect(clearLibrary.fn).toHaveBeenCalled());
    clearLibrary.calls[0].resolve();
    await waitFor(() => expect(fetchLibraryDetail.fn).toHaveBeenCalledWith({ libraryId: 'testtest' }));
  });

  it('Does not refetch the library if it matches', async () => {
    const library = libraryFactory();
    await render(library, genState(library));
    await process.nextTick(() => {
      expect(clearLibrary.fn).not.toHaveBeenCalled();
    });
  });

  it('Loads blocks', async () => {
    const library = libraryFactory();
    const blocks = makeN(blockFactoryLine([], { library }), 2);
    await render(library, genState(library, blocks));
    expect(screen.getByText(blocks[0].display_name)).toBeTruthy();
    expect(screen.getByText(blocks[1].display_name)).toBeTruthy();
  });

  it('Toggles Previews', async () => {
    const library = libraryFactory();
    const blocks = [blockFactory(undefined, { library })];
    await render(library, genState(library, blocks));
    expect(screen.getByTestId('block-preview')).toBeTruthy();
    screen.getAllByText('Hide Previews')[0].click();
    await waitFor(() => expect(() => screen.getByTestId('block-preview')).toThrow());
    expect(localStorage.getItem('showPreviews')).toBe('false');
  });

  it('Fetches block information', async () => {
    const library = libraryFactory();
    const blocks = [blockFactory({ id: 'testBlock' }, { library })];
    const storeConfig = genState(library, blocks);
    // Remove the local info about blocks.
    storeConfig.storeOptions.preloadedState[STORE_NAMES.BLOCKS].blocks = {};
    await render(library, storeConfig);
    // There should be no previews because this info hasn't loaded yet.
    await waitFor(() => expect(() => screen.getByTestId('block-preview')).toThrow());
    expect(initializeBlock.fn).toHaveBeenCalledWith({ blockId: 'testBlock' });
    initializeBlock.calls[0].dispatch(libraryBlockActions.libraryEnsureBlock({ blockId: 'testBlock' }));
    await waitFor(() => expect(fetchLibraryBlockView.fn).toHaveBeenCalledWith(
      {
        blockId: 'testBlock', viewName: 'student_view', viewSystem: 'studio',
      },
    ));
    expect(fetchLibraryBlockView.fn).toHaveBeenCalledTimes(1);
  });

  it('Fetches block LTI URL to clipboard', async () => {
    const library = libraryFactory({ allow_lti: true });
    const blocks = makeN(blockFactoryLine([], { library }), 2);

    await render(library, genState(library, blocks));
    expect(screen.getByText(blocks[0].display_name)).toBeTruthy();
    expect(screen.getByText(blocks[1].display_name)).toBeTruthy();

    const copyToClipboardButtons = screen.getAllByText('Copy LTI Url');
    expect(copyToClipboardButtons.length).toBe(2);

    copyToClipboardButtons[0].click();

    await waitFor(() => fetchBlockLtiUrl.calls[0].dispatch(
      libraryAuthoringActions.libraryBlockLtiUrlFetchRequest({ blockId: blocks[0].id }),
    ));

    expect(fetchBlockLtiUrl.fn).toHaveBeenCalledWith({ blockId: blocks[0].id });

    await waitFor(() => fetchBlockLtiUrl.calls[0].dispatch(
      libraryAuthoringActions.libraryAuthoringSuccess({
        value: { blockId: blocks[0], lti_url: 'a' },
        attr: 'ltiUrlClipboard',
      }),
    ));
  });

  it('Copy LTI URL not shown unless it is enabled', async () => {
    const library = libraryFactory();
    const blocks = makeN(blockFactoryLine([], { library }), 2);

    await render(library, genState(library, blocks));
    expect(screen.getByText(blocks[0].display_name)).toBeTruthy();
    expect(screen.getByText(blocks[1].display_name)).toBeTruthy();

    const copyToClipboardButtons = screen.queryAllByAltText('Copy LTI Url');
    expect(copyToClipboardButtons.length).toBe(0);
  });

  it('Adds a predefined block type', async () => {
    const library = libraryFactory({ type: LIBRARY_TYPES.VIDEO });
    await render(library, genState(library));
    const addButtons = screen.getAllByText('Add Video');
    // One's hidden by CSS, but the testing library wouldn't know that.
    expect(addButtons.length).toBe(3);
    addButtons[0].click();
    expect(createBlock.fn).toHaveBeenCalledWith({
      libraryId: library.id,
      data: {
        block_type: VIDEO_TYPE.block_type,
        definition_id: expect.any(String),
      },
      query: '',
      types: [],
      paginationParams,
    });
  });

  it('Adds a custom block type', async () => {
    const library = libraryFactory({
      blockTypes: [{ display_name: 'Test Type', block_type: 'test' }],
      type: LIBRARY_TYPES.COMPLEX,
    });
    await render(library, genState(library));
    screen.getByText('Advanced').click();
    const typeOption = await screen.findByText('Test Type', { ignore: 'option' });
    act(() => {
      typeOption.click();
    });
    await waitFor(() => expect(createBlock.fn).toHaveBeenCalledWith({
      libraryId: library.id,
      data: {
        block_type: 'test',
        definition_id: expect.any(String),
      },
      query: '',
      types: [],
      paginationParams,
    }));
  });

  [VIDEO_TYPE, PROBLEM_TYPE, HTML_TYPE].forEach((blockDef) => {
    it(`Adds a ${blockDef.display_name} block to a library`, async () => {
      const library = libraryFactory({ type: LIBRARY_TYPES.COMPLEX });
      await render(library, genState(library));
      screen.getByText('Advanced').click();
      const typeOption = await screen.findByText(blockDef.display_name, { ignore: 'option' });
      act(() => {
        typeOption.click();
      });
      expect(createBlock.fn).toHaveBeenCalledWith({
        libraryId: library.id,
        data: {
          block_type: blockDef.block_type,
          definition_id: expect.any(String),
        },
        query: '',
        types: [],
        paginationParams,
      });
    });
  });

  it('Searches for blocks', async () => {
    const library = libraryFactory();
    await render(library, genState(library));
    const search = screen.getByLabelText('Search...');
    act(() => {
      fireEvent.change(search, { target: { value: 'boop' } });
    });
    await waitFor(() => expect(searchLibrary.fn).toHaveBeenCalledWith({
      libraryId: library.id,
      query: 'boop',
      types: [],
      paginationParams,
    }));
  });

  it('Filters blocks by type', async () => {
    const library = libraryFactory();
    await render(library, genState(library));
    const filter = screen.getByTestId('filter-dropdown');
    act(() => {
      fireEvent.change(filter, { target: { value: 'html' } });
    });
    await waitFor(() => expect(searchLibrary.fn).toHaveBeenCalledWith({
      libraryId: library.id,
      query: '',
      types: ['html'],
      paginationParams,
    }));
  });

  it('Filters blocks by other types', async () => {
    const library = libraryFactory({
      blockTypes: [
        { block_type: 'squirrel', display_name: 'Squirrel' },
        { block_type: 'fox', display_name: 'Fox' },
        VIDEO_TYPE,
      ],
    });
    await render(library, genState(library));
    const filter = screen.getByTestId('filter-dropdown');
    act(() => {
      fireEvent.change(filter, { target: { value: '^' } });
    });
    await waitFor(() => expect(searchLibrary.fn).toHaveBeenCalledWith({
      libraryId: library.id,
      query: '',
      types: ['squirrel', 'fox'],
      paginationParams,
    }));
  });

  it('Commits changes', async () => {
    const library = libraryFactory({ has_unpublished_changes: true });
    await render(library, genState(library));
    screen.getByText('Publish').click();
    expect(commitLibraryChanges.fn).toHaveBeenCalledWith({ libraryId: library.id });
  });

  it('Reverts changes', async () => {
    const library = libraryFactory({ has_unpublished_changes: true });
    await render(library, genState(library));
    screen.getByText('Discard changes').click();
    expect(revertLibraryChanges.fn).toHaveBeenCalledWith({
      libraryId: library.id,
      paginationParams,
    });
  });

  it('Deletes a block', async () => {
    const library = libraryFactory();
    const block = blockFactory(undefined, { library });
    await render(library, genState(library, [block]));
    const del = screen.getByLabelText('Delete');
    act(() => {
      del.click();
    });
    const yes = await screen.findByText('Yes.');
    act(() => {
      yes.click();
    });
    await waitFor(
      () => expect(deleteLibraryBlock.fn).toHaveBeenCalledWith({ blockId: block.id }),
    );
  });
});