#include
#include
#include
#include
using namespace std;

vector list[20001];
int color[20001];

void dfs(int node, int c) {
	color[node] = c;
	for (int i = 0; i < list[node].size(); i++) {
		int next = list[node][i]; // next는 node와 연결되어있는 정점 중 가장 앞 숫자
		if (color[next] == 0) { // next가 아직 A/B 중 어디도 포함되지 않을 경우
			dfs(next, 3 - c); // next를 node와 반대 팀으로 배정한 후, 이동!
		}
	}
}

int main() {
	int T;
	cin >> T;
	

	while (T--) {

		int node, edge;
		cin >> node >> edge;


		for (int i = 0; i < edge; i++) { // list 작성
			int u, v;
			cin >> u >> v;
			list[u].push_back(v);
			list[v].push_back(u);
		}

		for (int i = 1; i <= node; i++) { // 전체 노드를 탐색
			if (color[i] == 0) {	// 노드 i의 색이 배정되어 있지 않으면,
				dfs(i, 1);			// i번째노트부터 dfs 탐색
			}
		}

		bool ok = true;

		for (int i = 1; i <= node; i++) {	// 1부터 끝까지 노드 탐색
			for (int k = 0; k < list[i].size(); k++) {	// 해당 노드에 연결된 모든 정점 탐색
				int j = list[i][k];
				if (color[i] == color[j]) {		// 만약 i번째 노드와 연결된 노드가 색이 같으면
					ok = false;					// ok를 false 로!
				}
			}
		}
		
		if (ok == false) cout << "NO" << endl;
		else cout << "YES" << endl;

		for (int i = 0; i <= node; i++) { 			// ★★★계속 index실수함.. node는 1 <= i <= node 이렇게!!
			list[i].clear();
			color[i] = 0;
		}

	}
	return 0;

}


dfs자체를 bool을 리턴하게 하는 풀이도 참조하장☆