Cannot query children in `<Portal>`s
The query commands (getByRole, getByTestId, etc.) fail to pick up children of <Portal>s.
The children of <Portal>s get rendered in a separate <div> from the content of the render call. The various query commands seem to use the container element, which is the first <div>, and fail to pick up anything in a portal:
import { expect, test } from 'vitest';
import { render } from '@solidjs/testing-library';
import { Portal } from 'solid-js/web';
test('Portal test', () => {
const { getByTestId, debug } = render(() => <>
<p data-testid='one'>One</p>
<Portal>
<p data-testid='two'>Two</p>
</Portal>
</>);
getByTestId('one'); // Succeeds
getByTestId('two'); // Throws an error
debug(); // Prints the following:
/*
<body>
<div>
<p data-testid="one">
One
</p>
</div>
<div>
<p data-testid="two">
Two
</p>
</div>
</body>
*/
});
One workaround is to use the baseElement property with a query selector, i.e. baseElement.querySelector('[data-testid="two"]'). However, Solid Testing Library reuses the <body> between render()s:
test('aaa', () => {
render(() => <p>test 1</p>);
render(() => <p>test 2</p>);
const res = render(() => <p>test 3</p>);
res.debug(); // Prints out the following:
/*
<body>
<div>
<p>test 1</p>
</div>
<div>
<p>test 2</p>
</div>
<div>
<p>test 3</p>
</div>
</body>
*/
});
So, if you have two tests in one file, they will both be rendered in the same document, and so you'll likely run into issues when using baseElement.querySelector, as it might select elements from a different test.
When using Vitest, adding this to a file solves the duplication issue for it and allows you to use baseElement.querySelector safely:
import { afterEach } from 'vitest';
import { cleanup } from '@solidjs/testing-library';
afterEach(() => {
cleanup();
});
However, this might break (I haven't tested it extensively) when rendering multiple times in one test(), as you'd have to call it manually in that case.
You don't need to cleanup afterwards, this is already done automatically. However, unless you choose isolation: true in the testing config, tests might influence each other.
You don't need to cleanup afterwards, this is already done automatically.
I saw that in the docs somewhere, but it didn't seem to work properly, and I had to call it manually.
Also, I'd rather not incur the slowdown of isolating all tests, just the ones in a specific file.
I don't want to encourage using isolation of tests at all costs, just explain the mechanism. Your issue might be timing- or error-related (tests could be cleaned up slightly delayed or may not be cleaned up after failure).
it wont work with a Portal because when you use Portal it will render html attached to the body, you need to use:
document.body.querySelector('[data-testid="two"]');
PS: I had the same issue and Github Copilot Chat told me to do it this way
Please use screen.get... accessible queries instead of CSS selectors.