Testing Library xếp query theo thứ tự càng gần cách người dùng tìm phần tử càng tốt:
1. Accessible queries — getByRole, getByLabelText, getByPlaceholderText, getByText, getByDisplayValue.
2. Semantic queries — getByAltText, getByTitle.
3. Test ID — getByTestId, dùng khi không còn cách nào khác.
// preferred: matches what the user sees and what a screen reader announces
screen.getByRole("button", { name: /save/i })
screen.getByLabelText("Email")
// last resort
screen.getByTestId("save-button")getByRole khớp theo vai trò ARIA (button, textbox, heading...) cộng accessible name. Lợi ích kép: test bám vào cái người dùng thật sự thấy, và nếu markup thiếu label thì query fail — test gián tiếp phát hiện lỗi accessibility.
getByTestId bám vào một thuộc tính chỉ tồn tại cho test, người dùng không thấy. Nó không kiểm tra được element có accessible hay không, và dễ giữ test xanh dù UI hỏng.
Khi data-testid là hợp lý: phần tử không có role/text ổn định (wrapper layout, canvas, item trong danh sách ảo hoá), text thay đổi theo i18n, hoặc cần chọn đúng một dòng trong bảng lặp lại. Ngay cả khi đó, nên kết hợp within(row).getByRole(...) thay vì gắn testid cho mọi thứ.