Code Monkey home page Code Monkey logo

Comments (22)

anapanadero avatar anapanadero commented on May 18, 2024 10

I continue with the same problem. For example:
<span>My name is (${name})</span>
The result for this code is:

<span> 
My name is ( 
 Ana
)
</span>

So getByText will fail saying Unable to find an element with the text when I try to do
screen.getByText(`My name is ${name})`)

What can I do to make this work?

from react-testing-library.

gnapse avatar gnapse commented on May 18, 2024 7

I'll take it, since I'll probably also have to do this to jest-dom's .toHaveTextContent ;)

(BTW, this is really a PR for dom-testing-library)

from react-testing-library.

tubbo avatar tubbo commented on May 18, 2024 4

This is also happening for me.

My JSX:

          <Text as="h1" size="large">
            Leave {data.community.name}?
          </Text>

The output:

            <h1
              class="c-PJLV c-PJLV-ddalwR-size-large"
            >
              Leave
              Foo
              ?
            </h1>

And the test:

  it('confirms with the user whether they wish to leave', async () => {
    expect(
      await screen.findByText('You are about to leave the Foo community'),
    ).toBeInTheDocument()
  })

Not sure if this is actually the same issue, but it's definitely the same symptom. Noticed it when I upgraded to React 17 and started using the new JSX transform.

I was able to work around this by changing my assertion to:

expect(
  await screen.findByText(/You are about to leave the(.*)Foo(.*)community./)
).toBeInTheDocument()

from react-testing-library.

maxcct avatar maxcct commented on May 18, 2024 1

That is a very good point. I guess then all you can do is ensure that you concatenate strings like this before inserting them into JSX.

from react-testing-library.

bdchauvette avatar bdchauvette commented on May 18, 2024 1

I'm running into the same problem, even with strings that don't have a space between the variable and normal text, e.g. <span>{volts}V<span>.

In this situation, the DOM node's textContent property contains a string without spaces, even though there are two Text nodes behind the scenes.

Live example: https://codesandbox.io/s/w718n5ojq7

from react-testing-library.

gnapse avatar gnapse commented on May 18, 2024

Given that in html any extra whitespace between words in text is not meaningful, and the resulting text shown to the user on screen is what you expect in your test above, I think it makes sense to take this into account when matching an element's text content.

Actually I am now wondering if .toHaveTextContent should also take this into account.

from react-testing-library.

kentcdodds avatar kentcdodds commented on May 18, 2024

Yes. We should update the matcher function in dom-testing-library to replace multiple spaces with one before it attempts to do any comparison. I consider this a bug and would love a pull request for it 👍

from react-testing-library.

DarrylD avatar DarrylD commented on May 18, 2024

I'm still having this issue, any idea why it would continue to add white spaces? Updated to the latest dom-testing-library.

from react-testing-library.

gnapse avatar gnapse commented on May 18, 2024

@DarrylD your best bet for others to be able to help is to provide a sample repository or codesandbox where the problem can be reproduced.

from react-testing-library.

maxcct avatar maxcct commented on May 18, 2024

I have also continued to experience the same issue, and was able to diagnose it (as far as my case goes, at least).

The problem is that the amendment to getText presupposes that when text is divided over multiple lines, the text on each line will constitute a separate word. Things go wrong when this is not the case; for example:

Pay
£
24.99

will end up as Pay £ 24.99. This problem is remedied if line 73 here is changed from .join(' ') to .join('').

Then, however, you'd be required to ensure a space is present after each separate word that's on a different line, so Pay would have to be Pay (i.e. with a space after it on the same line) in my example. Otherwise, there's no way to differentiate between words on different lines that should be separated by spaces on the one hand, and word fragments/characters on separate lines that should be concatenated on the other.

But I'm not really proposing this change be made, as you shouldn't have to ensure those spaces are present in your JSX.

from react-testing-library.

kentcdodds avatar kentcdodds commented on May 18, 2024

This is actually how HTML works. If you were to put this in the DOM:

<div>
Pay
£
24.99
</div>

The resulting output would appear to the user as:

Pay £ 24.99

This is why we do the join(' ') in dom-testing-library.

from react-testing-library.

kentcdodds avatar kentcdodds commented on May 18, 2024

Ah, this is tricky! What do you propose?

from react-testing-library.

bdchauvette avatar bdchauvette commented on May 18, 2024

Good question!

I'm not at all familiar with the internals of this library, but following @maxcct's lead, replacing join(' ') with join('') in getNodeText seems to do the trick.

I haven't made a proper fork of dom-testing-library yet, but I checked out master, ran the test suite locally with this change, and everything still passed.

I also wrote a quick (passing 🙌) test to see if the change works as expected across text nodes:

test('can get elements by matching their text across adjacent text nodes', () => {
  const textDiv = document.createElement('div')
  const textNodeContent = ['£', '24', '.', '99']
  textNodeContent
    .map(text => document.createTextNode(text))
    .forEach(textNode => textDiv.appendChild(textNode))

  const {container, queryByText} = render('<div />')
  container.appendChild(textDiv)
  expect(queryByText('£24.99')).toBeInTheDOM()
})

In any event, since this issue doesn't seem specific to React, maybe it would be better to move the discussion over to an issue and/or PR in dom-testing-library?

from react-testing-library.

kentcdodds avatar kentcdodds commented on May 18, 2024

Yeah, this should be talked about in dom-testing-library. Could you make a PR there and we can discuss how to solve this there. Thanks!

from react-testing-library.

klauskpm avatar klauskpm commented on May 18, 2024

I was able to work around this by changing my assertion to:

expect(
  await screen.findByText(/You are about to leave the(.*)Foo(.*)community./)
).toBeInTheDocument()

I'm using an older version, so maybe an update (not an option right now) would solve this, but I got it working with a solution similar to yours:

expect(screen.getByRole('button', { name: /Factors\s/ })).toBeInTheDocument();

from react-testing-library.

OttlikG avatar OttlikG commented on May 18, 2024

This is still an issue for me. Is there going to be any solution for this?
Can we consider reopening the issue?

My use case:

<Text textStyle="p12" color="typography.titleNormal" mb={6} data-testid="change-created-at">
   Created {format(createdAt, DEFAULT_DATE_PATTERN)}
</Text>

I worked around by querying data-testid and then assert with toHaveTextContent

it('should display created at text', () => {
    renderWithRouter(<Change {...props} />);

    expect(screen.getByTestId('change-created-at')).toHaveTextContent('Created 15 June 2022')
});

from react-testing-library.

alexander-schranz avatar alexander-schranz commented on May 18, 2024

Is there any issue about changing the behaviour how this is rendered and so snapshots for me it is just looks false if I have component like this:

<div>
    {charactersLeft} {translate('sulu_admin.characters_left')}
<div>

Is snapshoted as:

<div>
    -8
     
    sulu_admin.characters_left
</div>

Instead of and doesnt so represent what JSX is rendering:

<div>
    -8 sulu_admin.characters_left
</div>

from react-testing-library.

b3h3m0th avatar b3h3m0th commented on May 18, 2024

We managed to solve this problem by manually joining the strings like so:

<div>
    {charactersLeft + ' ' + translate('sulu_admin.characters_left')}
</div>

The code above generates the following (desired) snapshot result:

<div>
    -8 sulu_admin.characters_left
</div>

from react-testing-library.

evanjmg avatar evanjmg commented on May 18, 2024

getting something very similar here - very strange behaviour. This issue is not closed.

  • Snapshot - 0

    • Received + 1

    @@ -1,6 +1,7 @@

    +

it's adding new lines above my elements

from react-testing-library.

pstevovski avatar pstevovski commented on May 18, 2024

Any workaround for the above mentioned issues? This is a really old issue by now, and no idea why its marked as closed, when no specific answer was provided (by anyone) on how should we handle such scenarios.

I, as many others have already stated, am having an issue where the following JSX in my component:

<div>
  <h2>{status} text ({count})</h2>
</div>

is rendered like this in the tests:

<h2>
new
ads (
1
 )
 </h2>

And I cannot use getByText matcher to target it, as it says its unable to find the element. So.. how can I target it? I do not want to include data-testid attribute in this case (as this is part of a dynamically generated content for a table).

I tried using await screen.findByText(/new text (1)/gim) with the global and multi-line flags attached to the regex, but that is not working either.

from react-testing-library.

alexander-schranz avatar alexander-schranz commented on May 18, 2024

@pstevovski workaround string concat by @b3h3m0th should work in your case: #53 (comment)

from react-testing-library.

pstevovski avatar pstevovski commented on May 18, 2024

@alexander-schranz Thank you for your answer, and sorry for the late reply, no idea why but I didn't get any notification.

The answer provided by @b3h3m0th doesn't really work for my case in terms of practicality, I'd have to go and change a lot of the pieces trough out the application to convert them to be manually concatenated like that. And also, to be fair, that is just a "workaround" (as you mentioned), but then again accessing and reading dynamic values in React (or in JS in general) has better ways like we're all already using (either that be template literals or the way we use them in react).

===================

Closest thing I could work with was using getByText("Example text", { exact: false }), but even that didn't always worked.

I know this is an old issue, but I do believe that there really should be a way by RTL to be able to easily target these JSX variables with dynamic values.

==================

And on the other hand, RTL also has problems when targeting elements like:

<p>
   <span>Example</span> <strong>text</strong>
</p>

If wanted to target the entire p element based on the entire text, that wouldn't work like we're expecting. So workaround at least for that type of issue would be a helper matcher function like:

type Query = (queryMatcher: MatcherFunction) => HTMLElement;

/**
 *
 * Helper matcher function to be used together with React Testing Library matchers.
 *
 * Helps find an element in the rendered testing UI that has nested HTML elements:
 *
 * @example
 *  <h1>
 *    <span>Title</span> with
 *    <strong>nested</strong> elements.
 *  </h1>
 *
 * @param query The query matcher function to be used, provided by RTL
 * @param text The text by which we want to find the targeted element
 *
 * @returns The targeted element (if found). Otherwise, throws an error.
 *
 */
export const getByTextWithMarkup = (query: Query, text: string): HTMLElement => {
  return query((_content: string, node: any) => {
    const hasText = (node: HTMLElement) => node.textContent === text;
    const childrenDontHaveText = Array.from(node.children).every(
      child => !hasText(child as HTMLElement),
    );
    return hasText(node) && childrenDontHaveText;
  });
};

Leaving this here as it might help someone out there (although it doesn't really help with the main issue that was reported).

from react-testing-library.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.