findByRole not working properly after element is present in DOM
See original GitHub issueI have a markup that some elements visibility depends on a condition. Something like this:
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-test',
template: `
<form [formGroup]="formGroup">
<mat-form-field>
<mat-label>Number</mat-label>
<input matInput required formControlName="number" />
</mat-form-field>
<ng-container *ngIf="formGroup.get('number').valid">
<mat-form-field>
<mat-label>Holder</mat-label>
<input matInput required formControlName="holder" />
</mat-form-field>
<mat-form-field>
<mat-label>Expiry</mat-label>
<input matInput required formControlName="expiry" />
</mat-form-field>
<mat-form-field>
<mat-label>CVV</mat-label>
<input matInput required formControlName="cvv" />
</mat-form-field>
</ng-container>
</form>
`,
})
export class TestComponent {
readonly formGroup = this.formBuilder.group({
number: ['', [Validators.required, Validators.minlength(16), ...otherValidators]],
holder: ['', [Validators.required, Validators.minlength(5), ...otherValidators]],
expiry: ['', [Validators.required, Validators.minlength(7), ...otherValidators]],
cvv: ['', [Validators.required, Validators.minlength(3), ...otherValidators]],
});
constructor(private readonly formBuilder: FormBuilder) {}
}
//////// Test file
async function setup() {
const { rerender } = await render(TestComponent);
const numberHtmlElementRef = screen.getByRole('textbox', { name: /number/i });
const holderHtmlElementRef = screen.findByRole('textbox', { name: /holder/i });
const expiryHtmlElementRef = screen.findByRole('textbox', { name: /expiry/i });
const cvvHtmlElementRef = screen.findByRole('textbox', { name: /cvv/i });
return {
numberHtmlElementRef,
holderHtmlElementRef,
expiryHtmlElementRef,
cvvHtmlElementRef,
rerender,
} as const;
}
describe(TestComponent.name, () => {
test('someDescription', async () => {
const {
numberHtmlElementRef,
holderHtmlElementRef,
expiryHtmlElementRef,
cvvHtmlElementRef,
} = await setup();
await expect(holderHtmlElementRef).rejects.toThrow(/Unable to find/i); // ok
await expect(expiryHtmlElementRef).rejects.toThrow(/Unable to find/i); // ok
await expect(cvvHtmlElementRef).rejects.toThrow(/Unable to find/i); // ok
await userEvent.type(numberHtmlElementRef, '5353107424870314');
expect(numberHtmlElementRef).toBeValid(); // ok
await expect(holderHtmlElementRef).resolves.toBeInTheDocument(); // fail
await expect(expiryHtmlElementRef).resolves.toBeInTheDocument(); // fail
await expect(cvvHtmlElementRef).resolves.toBeInTheDocument(); // fail
// If I don't reuse the element, like this, it works (or using `queryBy`/`getBy`):
await expect(screen.findByRole('textbox', { name: /holder/i })).resolves.toBeInTheDocument(); // ok
screen.getByRole('textbox', { name: /holder/i }); // ok
});
}
So, the fields holder
, expiry
and cvv
are visible once number
is valid, but the tests keep failing. I noticed that if I query it again, using getByRole(...)
to check if it’s present in document, it works, but shouldn’t findByRole(...)
works in this case?
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (5 by maintainers)
Top Results From Across the Web
byRole is not returning the DOM element - Stack Overflow
I have tried all the following approach to wait for element to appear in DOM: waitFor; findByRole instead of getByRole. in both the...
Read more >ByRole | Testing Library
As a result, querying a superclass role like checkbox will not include elements with a subclass role like switch .
Read more >findByRole function - rtl.dom.queries library - Dart API
Returns a future with a single element value with the given role value, defaulting to an exact match after waiting 1000ms (or the...
Read more >How To Test a React App with Jest and React Testing Library
After running npm test for the first time, you will see this output in the terminal: Output. No tests found related to files...
Read more >Making sure you're using the correct query - Tim Deschryver
Instead of selecting DOM elements via their id attributes or classes, ... There are some cases that this query will not be able...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I tried this with RTL and the behavior is the same. This is also the intended behavior because we keep a reference, but we have to re-query the element as you’ve also have noticed.
To not repeat the query you can wrap it inside a factory method:
RTL reproduction
Thanks for the explanation 😃