@testing-library/dom#within JavaScript Examples

The following examples show how to use @testing-library/dom#within. 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: HeatmapMetadataTrackSettings.test.jsx    From ui with MIT License 5 votes vote down vote up
checkReorderableListState = (contentList, enabledList, items) => {
  items.forEach((item, index) => {
    expect(item).toHaveTextContent(contentList[index]);

    const expectedAriaChecked = enabledList[index] ? 'true' : 'false';
    expect(within(item).getByRole('switch')).toHaveAttribute('aria-checked', expectedAriaChecked);
  });
}
Example #2
Source File: HeatmapMetadataTrackSettings.test.jsx    From ui with MIT License 5 votes vote down vote up
describe('HeatmapMetadataTrackSettings', () => {
  it('Renders correctly', async () => {
    await loadAndRenderDefault();

    const items = screen.getAllByTestId('reorderableListItem');

    checkReorderableListState(
      ['louvain clusters', 'Custom cell sets', 'Samples'],
      [true, false, false],
      items,
    );
  });

  it('Can enable and reorder correctly', async () => {
    await loadAndRenderDefault();

    let items = screen.getAllByTestId('reorderableListItem');

    // When samples is enabled
    act(() => {
      userEvent.click(within(items[2]).getByRole('switch'));
    });

    items = screen.getAllByTestId('reorderableListItem');

    checkReorderableListState(
      ['louvain clusters', 'Samples', 'Custom cell sets'],
      [true, true, false],
      items,
    );

    // When louvain is moved down
    act(() => {
      const downButton = within(items[0]).getAllByRole('button')[1];

      userEvent.click(downButton);
    });

    items = screen.getAllByTestId('reorderableListItem');

    // Louvain is now second
    checkReorderableListState(
      ['Samples', 'louvain clusters', 'Custom cell sets'],
      [true, true, false],
      items,
    );

    // When louvain is attempted to be moved down again
    items = screen.getAllByTestId('reorderableListItem');
    act(() => {
      const downButton = within(items[1]).getAllByRole('button')[1];

      userEvent.click(downButton);
    });

    items = screen.getAllByTestId('reorderableListItem');

    // Nothing changes, because custom cell sets is disabled
    checkReorderableListState(
      ['Samples', 'louvain clusters', 'Custom cell sets'],
      [true, true, false],
      items,
    );
  });
});
Example #3
Source File: index.test.jsx    From ui with MIT License 4 votes vote down vote up
describe('Marker heatmap plot', () => {
  beforeAll(async () => {
    await preloadAll();
  });

  beforeEach(async () => {
    jest.clearAllMocks();

    seekFromS3
      .mockReset()
      // load gene list
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((Etag) => mockWorkerResponses[Etag])
      // load gene expression
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((Etag) => mockWorkerResponses[Etag]);

    enableFetchMocks();
    fetchMock.resetMocks();
    fetchMock.doMock();
    fetchMock.mockIf(/.*/, mockAPI(defaultResponses));

    storeState = makeStore();

    // Set up state for backend status
    await storeState.dispatch(loadBackendStatus(experimentId));
  });

  it('Loads controls and elements', async () => {
    await renderHeatmapPage(storeState);

    expect(screen.getByText(/Gene selection/i)).toBeInTheDocument();
    expect(screen.getByText(/Select data/i)).toBeInTheDocument();
    expect(screen.getByText(/Cluster guardlines/i)).toBeInTheDocument();
    expect(screen.getByText(/Metadata tracks/i)).toBeInTheDocument();
    expect(screen.getByText(/Group by/i)).toBeInTheDocument();
    expect(screen.getByText(/Expression values/i)).toBeInTheDocument();
    expect(screen.getByText(/Main schema/i)).toBeInTheDocument();
    expect(screen.getByText(/Colours/i)).toBeInTheDocument();
    expect(screen.getByText(/Legend/i)).toBeInTheDocument();
  });
  
  it('Loads the plot', async () => {
    await renderHeatmapPage(storeState);

    expect(screen.getByRole('graphics-document', { name: 'Marker heatmap' })).toBeInTheDocument();
  });

  it('Shows an error message if marker genes failed to load', async () => {
    seekFromS3
      .mockReset()
      // load genes list
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((Etag) => mockWorkerResponses[Etag])
      // throw error on marker genes load
      .mockImplementationOnce(() => null)
      .mockImplementationOnce(() => { throw new Error('Not found'); });

    await renderHeatmapPage(storeState);

    // It shouldn't show the plot
    expect(screen.queryByRole('graphics-document', { name: 'Marker heatmap' })).toBeNull();

    // There is an error message
    expect(screen.getByText(/Could not load marker genes/i)).toBeInTheDocument();
  });

  it('loads marker genes on specifying new number of genes per cluster', async () => {
    await renderHeatmapPage(storeState);

    // Check that initially there are 5 marker genes - the default
    markerGenesData5.order.forEach((geneName) => {
      expect(screen.getByText(geneName)).toBeInTheDocument();
    });

    await act(async () => {
      userEvent.click(screen.getByText('Marker genes'));
    });

    expect(screen.getByText('Number of marker genes per cluster')).toBeInTheDocument();

    const nGenesInput = screen.getByRole('spinbutton', { name: 'Number of genes input' });

    userEvent.type(nGenesInput, '{backspace}2');

    await act(async () => {
      userEvent.click(screen.getByText('Run'));
    });

    // Go back to "Custom Genes" and check the number of genes
    await act(async () => {
      userEvent.click(screen.getByText('Custom genes'));
    });

    // The genes in Data 2 should exist
    markerGenesData2.order.forEach((geneName) => {
      expect(screen.getByText(geneName)).toBeInTheDocument();
    });
  });

  it('adds genes correctly into the plot', async () => {
    seekFromS3
      .mockReset()
      // load genes list
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((Etag) => mockWorkerResponses[Etag])
      // 1st load
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((ETag) => mockWorkerResponses[ETag])
      // 2nd load
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((ETag) => mockWorkerResponses[ETag]);

    await renderHeatmapPage(storeState);

    // Add in a new gene
    // This is done because we can not insert text into the genes list input
    const genesToLoad = [...markerGenesData5.order, 'FAKEGENE'];

    await act(async () => {
      await storeState.dispatch(loadGeneExpression(experimentId, genesToLoad, plotUuid));
    });

    expect(screen.getByText('FAKEGENE')).toBeInTheDocument();

    // The returned value is a HTML NodeList
    const genesContainer = screen.getByText('FAKEGENE').closest('div[class*=selector]');

    const displayedGenesList = getDisplayedGenes(genesContainer);

    // Check that the genes is ordered correctly.
    // This means that FAKEGENE should not be the last in the genes list
    expect(_.isEqual(displayedGenesList, genesToLoad)).toEqual(false);
  });

  it('Shows an error message if gene expression fails to load', async () => {
    seekFromS3
      .mockReset()
      // load genes list
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((Etag) => mockWorkerResponses[Etag])
      // throw error on gene expression load
      .mockImplementationOnce(() => null)
      .mockImplementationOnce(() => { throw new Error('Not found'); });

    await renderHeatmapPage(storeState);

    const genesToLoad = [...markerGenesData5.order, 'FAKEGENE'];

    await act(async () => {
      await storeState.dispatch(loadGeneExpression(experimentId, genesToLoad, plotUuid));
    });

    // It shouldn't show the plot
    expect(screen.queryByRole('graphics-document', { name: 'Marker heatmap' })).toBeNull();

    // There is an error message
    expect(screen.getByText(/Could not load gene expression data/i)).toBeInTheDocument();
  });

  it('removing a gene keeps the sorted order without re-sorting', async () => {
    seekFromS3
      .mockReset()
      // load genes list
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((Etag) => mockWorkerResponses[Etag])
      // 1st load
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((ETag) => mockWorkerResponses[ETag])
      // 2nd load
      .mockImplementationOnce(() => null)
      .mockImplementationOnce((ETag) => mockWorkerResponses[ETag]);

    await renderHeatmapPage(storeState);

    // Setting up so that there is an inserted gene in the list
    const genesToLoad = [...markerGenesData5.order, 'FAKEGENE'];

    await act(async () => {
      // This is done because we can not insert text into the genes list input
      await storeState.dispatch(loadGeneExpression(experimentId, genesToLoad, plotUuid));
    });

    expect(screen.getByText('FAKEGENE')).toBeInTheDocument();

    // The returned value is a HTML NodeList
    const genesContainer = screen.getByText('FAKEGENE').closest('div[class*=selector]');
    const genesListBeforeRemoval = getDisplayedGenes(genesContainer);

    // Removing the 5th gene from the list
    // genesListBeforeRemoval is modified - splice removes the item from the list
    const geneToRemove = genesListBeforeRemoval.splice(5, 1);
    const geneRemoveButton = screen.getByText(geneToRemove).nextSibling;

    userEvent.click(geneRemoveButton);

    // Get newly displayed genes after the removal
    const genesListAfterRemoval = getDisplayedGenes(genesContainer);

    // The list of displayed genes should be in the same order as the displayed genes
    expect(_.isEqual(genesListAfterRemoval, genesListBeforeRemoval)).toEqual(true);
  });

  it('loads the tabs under gene selection', async () => {
    await renderHeatmapPage(storeState);

    expect(screen.getByText(/Add\/Remove genes/i)).toBeInTheDocument();
    expect(screen.getByText(/Search for and re-order genes/i)).toBeInTheDocument();
  });

  it('switches tabs and removes genes within the tree', async () => {
    await renderHeatmapPage(storeState);

    await act(async () => {
      userEvent.click(screen.getByText('Search for and re-order genes'));
    });
    // note: clicking another tab doesn't remove previous tab from screen
    // screen.getByText will find multiples of the same gene -> use within(geneTree)

    const geneTree = screen.getByRole('tree');

    // The genes in Data 5 should be in the tree
    markerGenesData5.order.forEach((geneName) => {
      expect(within(geneTree).getByText(geneName)).toBeInTheDocument();
    });

    // Remove a gene using the X button
    const genesListBeforeRemoval = getTreeGenes(geneTree);

    const geneToRemove = within(geneTree).getByText(genesListBeforeRemoval[1]);

    const geneRemoveButton = geneToRemove.nextSibling.firstChild;

    userEvent.click(geneRemoveButton);

    const genesListAfterRemoval = getTreeGenes(geneTree);

    // remove element from list manually to compare
    genesListBeforeRemoval.splice(1, 1);

    // The gene should be deleted from the list
    expect(_.isEqual(genesListAfterRemoval, genesListBeforeRemoval)).toEqual(true);
  });

  it('searches for genes and adds a valid gene', async () => {
    await renderHeatmapPage(storeState);

    await act(async () => {
      userEvent.click(screen.getByText('Search for and re-order genes'));
    });

    // check placeholder text is loaded
    expect(screen.getByText('Search for genes...')).toBeInTheDocument();

    const searchBox = screen.getByRole('combobox');

    // remove a gene to check if genes can be added
    const geneTree = screen.getByRole('tree');
    const geneToRemove = within(geneTree).getByText('Tmem176a');

    const geneRemoveButton = geneToRemove.nextSibling.firstChild;

    userEvent.click(geneRemoveButton);

    // search for genes using lowercase
    userEvent.type(searchBox, 'tmem');

    // antd creates multiple elements for options
    // find option element by title, clicking on element with role='option' does nothing
    const option = screen.getByTitle('Tmem176a');

    await act(async () => {
      // the element has pointer-events set to 'none', skip check
      // based on https://stackoverflow.com/questions/61080116
      userEvent.click(option, undefined, { skipPointerEventsCheck: true });
    });

    // check the search text is cleared after selecting a valid option
    expect(searchBox.value).toBe('');

    // check the selected gene was added
    expect(within(geneTree).getByText('Tmem176a')).toBeInTheDocument();
  });

  it('adds an already loaded gene and clears the input', async () => {
    await renderHeatmapPage(storeState);

    await act(async () => {
      userEvent.click(screen.getByText('Search for and re-order genes'));
    });

    const searchBox = screen.getByRole('combobox');

    userEvent.type(searchBox, 'tmem');

    // this finds option for selection box in 1st tab and search box, use second element
    const option = screen.getAllByTitle('Tmem176a')[1];

    await act(async () => {
      userEvent.click(option, undefined, { skipPointerEventsCheck: true });
    });

    // search box shouldn't clear when selecting an already loaded gene
    expect(searchBox.value).toBe('tmem');

    // clear button is automatically generated by antd and cannot be easily accessed
    const clearButton = searchBox.closest('div[class*=ant-select-auto-complete]').lastChild;

    userEvent.click(clearButton);

    expect(searchBox.value).toBe('');
  });
});